summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/00-COMPILE-LINK-RUN.txt2
-rwxr-xr-xindra/cmake/00-Common.cmake2
-rwxr-xr-xindra/cmake/CARes.cmake21
-rwxr-xr-xindra/cmake/CMakeLists.txt2
-rwxr-xr-xindra/cmake/FindCARes.cmake48
-rwxr-xr-xindra/cmake/LLCoreHttp.cmake2
-rwxr-xr-xindra/cmake/LLMessage.cmake2
-rwxr-xr-xindra/cmake/Variables.cmake6
-rwxr-xr-xindra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llcallbacklist.cpp230
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llcallbacklist.h (renamed from indra/newview/llcallbacklist.h)21
-rwxr-xr-xindra/llcommon/lleventcoro.cpp32
-rwxr-xr-xindra/llcommon/lleventcoro.h87
-rwxr-xr-xindra/llcommon/llmemory.cpp3
-rwxr-xr-xindra/llcommon/llmemory.h9
-rw-r--r--indra/llcommon/llmutex.h4
-rwxr-xr-xindra/llcommon/llprocess.cpp13
-rw-r--r--indra/llcommon/llsdjson.cpp48
-rw-r--r--indra/llcommon/llsdjson.h18
-rwxr-xr-xindra/llcommon/llstl.h4
-rw-r--r--indra/llcommon/lluriparser.cpp10
-rwxr-xr-xindra/llcommon/tests/lleventcoro_test.cpp50
-rwxr-xr-xindra/llcorehttp/CMakeLists.txt6
-rwxr-xr-xindra/llcorehttp/_httplibcurl.cpp35
-rwxr-xr-xindra/llcorehttp/_httplibcurl.h8
-rwxr-xr-xindra/llcorehttp/_httpopcancel.h5
-rwxr-xr-xindra/llcorehttp/_httpoperation.cpp123
-rwxr-xr-xindra/llcorehttp/_httpoperation.h52
-rwxr-xr-xindra/llcorehttp/_httpoprequest.cpp43
-rwxr-xr-xindra/llcorehttp/_httpoprequest.h3
-rwxr-xr-xindra/llcorehttp/_httpopsetget.h3
-rwxr-xr-xindra/llcorehttp/_httpopsetpriority.h1
-rwxr-xr-xindra/llcorehttp/_httppolicy.cpp49
-rwxr-xr-xindra/llcorehttp/_httppolicy.h8
-rwxr-xr-xindra/llcorehttp/_httpreadyqueue.h6
-rwxr-xr-xindra/llcorehttp/_httpreplyqueue.cpp19
-rwxr-xr-xindra/llcorehttp/_httpreplyqueue.h23
-rwxr-xr-xindra/llcorehttp/_httprequestqueue.cpp15
-rwxr-xr-xindra/llcorehttp/_httprequestqueue.h8
-rwxr-xr-xindra/llcorehttp/_httpretryqueue.h6
-rwxr-xr-xindra/llcorehttp/_httpservice.cpp19
-rwxr-xr-xindra/llcorehttp/examples/http_texture_load.cpp11
-rwxr-xr-xindra/llcorehttp/httpcommon.cpp179
-rwxr-xr-xindra/llcorehttp/httpcommon.h16
-rwxr-xr-xindra/llcorehttp/httphandler.h3
-rwxr-xr-xindra/llcorehttp/httprequest.cpp217
-rwxr-xr-xindra/llcorehttp/httprequest.h35
-rwxr-xr-xindra/llcorehttp/llhttpconstants.cpp (renamed from indra/llmessage/llhttpconstants.cpp)91
-rwxr-xr-xindra/llcorehttp/llhttpconstants.h (renamed from indra/llmessage/llhttpconstants.h)7
-rwxr-xr-xindra/llcorehttp/tests/llcorehttp_test.cpp2
-rwxr-xr-xindra/llcorehttp/tests/test_httpoperation.hpp20
-rwxr-xr-xindra/llcorehttp/tests/test_httprequest.hpp187
-rwxr-xr-xindra/llcorehttp/tests/test_httprequestqueue.hpp32
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp13
-rwxr-xr-xindra/llimage/llimagebmp.cpp14
-rwxr-xr-xindra/llimage/llimagetga.cpp6
-rwxr-xr-xindra/llmath/llvolume.cpp55
-rwxr-xr-xindra/llmath/llvolume.h10
-rwxr-xr-xindra/llmath/m4math.cpp13
-rwxr-xr-xindra/llmath/m4math.h5
-rwxr-xr-xindra/llmessage/CMakeLists.txt20
-rwxr-xr-xindra/llmessage/llares.cpp839
-rwxr-xr-xindra/llmessage/llares.h583
-rwxr-xr-xindra/llmessage/llareslistener.cpp104
-rwxr-xr-xindra/llmessage/llareslistener.h53
-rwxr-xr-xindra/llmessage/llassetstorage.cpp1
-rwxr-xr-xindra/llmessage/llassetstorage.h1
-rwxr-xr-xindra/llmessage/llavatarnamecache.cpp2
-rw-r--r--indra/llmessage/llcoproceduremanager.cpp55
-rw-r--r--indra/llmessage/llcorehttputil.cpp333
-rw-r--r--indra/llmessage/llcorehttputil.h175
-rwxr-xr-xindra/llmessage/llcurl.cpp2042
-rwxr-xr-xindra/llmessage/llcurl.h462
-rw-r--r--indra/llmessage/llexperiencecache.cpp363
-rw-r--r--indra/llmessage/llexperiencecache.h38
-rwxr-xr-xindra/llmessage/llhttpassetstorage.cpp1454
-rwxr-xr-xindra/llmessage/llhttpassetstorage.h159
-rwxr-xr-xindra/llmessage/llhttpclient.cpp677
-rwxr-xr-xindra/llmessage/llhttpclient.h201
-rwxr-xr-xindra/llmessage/llhttpclientinterface.h45
-rw-r--r--indra/llmessage/llhttpsdhandler.cpp30
-rw-r--r--indra/llmessage/llhttpsdhandler.h19
-rwxr-xr-xindra/llmessage/llproxy.cpp23
-rwxr-xr-xindra/llmessage/llproxy.h16
-rwxr-xr-xindra/llmessage/llsdrpcclient.cpp245
-rwxr-xr-xindra/llmessage/llsdrpcclient.h329
-rwxr-xr-xindra/llmessage/llsdrpcserver.cpp339
-rwxr-xr-xindra/llmessage/llsdrpcserver.h360
-rwxr-xr-xindra/llmessage/lltrustedmessageservice.cpp1
-rwxr-xr-xindra/llmessage/llurlrequest.cpp783
-rwxr-xr-xindra/llmessage/llurlrequest.h357
-rwxr-xr-xindra/llmessage/message.cpp3
-rwxr-xr-xindra/llmessage/message.h1
-rwxr-xr-xindra/llplugin/llpluginclassmedia.cpp8
-rwxr-xr-xindra/llplugin/llpluginclassmedia.h9
-rwxr-xr-xindra/llprimitive/CMakeLists.txt10
-rw-r--r--indra/llprimitive/lldaeloader.cpp2436
-rw-r--r--indra/llprimitive/lldaeloader.h107
-rwxr-xr-xindra/llprimitive/llmodel.cpp1313
-rwxr-xr-xindra/llprimitive/llmodel.h129
-rw-r--r--indra/llprimitive/llmodelloader.cpp640
-rw-r--r--indra/llprimitive/llmodelloader.h212
-rwxr-xr-xindra/llprimitive/llprimitive.cpp52
-rwxr-xr-xindra/llprimitive/llprimitive.h5
-rwxr-xr-xindra/llprimitive/llprimtexturelist.cpp11
-rwxr-xr-xindra/llprimitive/llprimtexturelist.h2
-rwxr-xr-xindra/llprimitive/lltextureentry.cpp4
-rwxr-xr-xindra/llprimitive/lltextureentry.h8
-rwxr-xr-xindra/llui/CMakeLists.txt5
-rwxr-xr-xindra/llui/lldockablefloater.cpp2
-rw-r--r--indra/llui/llfolderviewitem.cpp45
-rwxr-xr-xindra/llui/llfolderviewitem.h4
-rwxr-xr-xindra/llui/llfolderviewmodel.h2
-rwxr-xr-xindra/llui/llmenugl.cpp58
-rwxr-xr-xindra/llui/llmenugl.h5
-rwxr-xr-xindra/llui/llsearcheditor.cpp13
-rwxr-xr-xindra/llui/llsearcheditor.h2
-rwxr-xr-xindra/llui/lltextbase.cpp53
-rwxr-xr-xindra/llui/lltextbase.h8
-rwxr-xr-xindra/llui/llurlentry.cpp92
-rwxr-xr-xindra/llui/llurlentry.h24
-rwxr-xr-xindra/llui/llurlregistry.cpp47
-rwxr-xr-xindra/llui/tests/llurlentry_test.cpp194
-rw-r--r--indra/llwindow/llopenglview-objc.mm6
-rwxr-xr-xindra/llwindow/llwindow.cpp4
-rwxr-xr-xindra/llwindow/llwindowmacosx-objc.h1
-rwxr-xr-xindra/newview/CMakeLists.txt22
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rwxr-xr-xindra/newview/app_settings/settings.xml35
-rwxr-xr-xindra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl3
-rwxr-xr-xindra/newview/app_settings/shaders/class1/deferred/bumpF.glsl24
-rwxr-xr-xindra/newview/installers/windows/installer_template.nsi4
-rwxr-xr-xindra/newview/llaccountingcostmanager.cpp87
-rwxr-xr-xindra/newview/llaccountingcostmanager.h7
-rwxr-xr-xindra/newview/llagent.cpp2
-rwxr-xr-xindra/newview/llagent.h3
-rwxr-xr-xindra/newview/llagentdata.cpp1
-rwxr-xr-xindra/newview/llagentdata.h1
-rwxr-xr-xindra/newview/llaisapi.cpp22
-rwxr-xr-xindra/newview/llaisapi.h2
-rwxr-xr-xindra/newview/llappcorehttp.cpp26
-rwxr-xr-xindra/newview/llappcorehttp.h2
-rwxr-xr-xindra/newview/llappearancemgr.cpp197
-rwxr-xr-xindra/newview/llappearancemgr.h8
-rwxr-xr-xindra/newview/llappviewer.cpp72
-rwxr-xr-xindra/newview/llappviewermacosx.cpp50
-rwxr-xr-xindra/newview/llavatariconctrl.cpp1
-rw-r--r--indra/newview/llavatarrenderinfoaccountant.cpp4
-rw-r--r--[-rwxr-xr-x]indra/newview/llcallbacklist.cpp0
-rwxr-xr-xindra/newview/llcallingcard.cpp25
-rwxr-xr-xindra/newview/llcallingcard.h3
-rwxr-xr-xindra/newview/llchannelmanager.cpp3
-rwxr-xr-xindra/newview/llchathistory.cpp4
-rwxr-xr-xindra/newview/llchiclet.cpp8
-rwxr-xr-xindra/newview/llchicletbar.cpp3
-rwxr-xr-xindra/newview/llcommandhandler.cpp12
-rwxr-xr-xindra/newview/llcompilequeue.cpp5
-rwxr-xr-xindra/newview/llconversationlog.h3
-rwxr-xr-xindra/newview/llconversationmodel.cpp19
-rwxr-xr-xindra/newview/lldrawpoolavatar.cpp22
-rwxr-xr-xindra/newview/lldrawpoolbump.cpp1
-rwxr-xr-xindra/newview/llestateinfomodel.cpp2
-rwxr-xr-xindra/newview/lleventpoll.cpp18
-rwxr-xr-xindra/newview/lleventpoll.h1
-rw-r--r--indra/newview/llexperienceassociationresponder.cpp97
-rw-r--r--indra/newview/llexperienceassociationresponder.h58
-rwxr-xr-xindra/newview/llfacebookconnect.cpp32
-rwxr-xr-xindra/newview/llfavoritesbar.cpp384
-rwxr-xr-xindra/newview/llfavoritesbar.h26
-rwxr-xr-xindra/newview/llfeaturemanager.cpp6
-rwxr-xr-xindra/newview/llfilepicker.cpp4
-rw-r--r--indra/newview/llflickrconnect.cpp17
-rwxr-xr-xindra/newview/llfloaterabout.cpp94
-rwxr-xr-xindra/newview/llfloaterabout.h3
-rwxr-xr-xindra/newview/llfloateravatarpicker.cpp2
-rwxr-xr-xindra/newview/llfloaterbump.cpp32
-rwxr-xr-xindra/newview/llfloaterbump.h4
-rw-r--r--indra/newview/llfloaterexperienceprofile.cpp283
-rw-r--r--indra/newview/llfloaterexperienceprofile.h6
-rw-r--r--indra/newview/llfloaterexperiences.cpp5
-rw-r--r--indra/newview/llfloaterfacebook.cpp6
-rwxr-xr-xindra/newview/llfloaterimcontainer.cpp74
-rwxr-xr-xindra/newview/llfloaterimcontainer.h2
-rwxr-xr-xindra/newview/llfloaterjoystick.cpp14
-rwxr-xr-xindra/newview/llfloaterjoystick.h5
-rwxr-xr-xindra/newview/llfloaterland.cpp3
-rwxr-xr-xindra/newview/llfloatermarketplacelistings.cpp2
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp3053
-rwxr-xr-xindra/newview/llfloatermodelpreview.h132
-rwxr-xr-xindra/newview/llfloatermodeluploadbase.cpp2
-rw-r--r--indra/newview/llfloaternotificationstabbed.cpp575
-rw-r--r--indra/newview/llfloaternotificationstabbed.h174
-rwxr-xr-xindra/newview/llfloateroutbox.cpp623
-rwxr-xr-xindra/newview/llfloateroutbox.h116
-rwxr-xr-xindra/newview/llfloaterperms.cpp49
-rwxr-xr-xindra/newview/llfloaterpreference.cpp25
-rwxr-xr-xindra/newview/llfloaterpreference.h3
-rwxr-xr-xindra/newview/llfloaterregioninfo.cpp58
-rwxr-xr-xindra/newview/llfloaterregioninfo.h2
-rwxr-xr-xindra/newview/llfloaterreporter.cpp4
-rwxr-xr-xindra/newview/llfloaterscriptlimits.cpp8
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp8
-rwxr-xr-xindra/newview/llfloatertos.cpp36
-rwxr-xr-xindra/newview/llfloatertos.h2
-rwxr-xr-xindra/newview/llfloatertranslationsettings.cpp64
-rwxr-xr-xindra/newview/llfloatertranslationsettings.h2
-rwxr-xr-xindra/newview/llfloaterurlentry.cpp2
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp6
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.cpp23
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.h1
-rwxr-xr-xindra/newview/llgroupmgr.cpp93
-rwxr-xr-xindra/newview/llgroupmgr.h7
-rwxr-xr-xindra/newview/llhttpretrypolicy.cpp47
-rwxr-xr-xindra/newview/llhttpretrypolicy.h2
-rwxr-xr-xindra/newview/llimview.cpp4
-rwxr-xr-xindra/newview/llinventorybridge.cpp291
-rwxr-xr-xindra/newview/llinventorybridge.h12
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp160
-rwxr-xr-xindra/newview/llinventoryfunctions.h10
-rwxr-xr-xindra/newview/llinventorymodel.cpp8
-rwxr-xr-xindra/newview/llinventorymodel.h6
-rwxr-xr-xindra/newview/llinventorymodelbackgroundfetch.cpp11
-rwxr-xr-xindra/newview/llinventoryobserver.cpp2
-rwxr-xr-xindra/newview/llinventorypanel.cpp24
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp2
-rwxr-xr-xindra/newview/lllocationinputctrl.cpp5
-rwxr-xr-xindra/newview/lllogchat.cpp16
-rwxr-xr-xindra/newview/lllogchat.h1
-rwxr-xr-xindra/newview/llmanipscale.cpp16
-rwxr-xr-xindra/newview/llmaniptranslate.cpp8
-rwxr-xr-xindra/newview/llmarketplacefunctions.cpp1388
-rwxr-xr-xindra/newview/llmarketplacefunctions.h22
-rwxr-xr-xindra/newview/llmaterialmgr.cpp362
-rw-r--r--indra/newview/llmaterialmgr.h7
-rwxr-xr-xindra/newview/llmediactrl.cpp23
-rwxr-xr-xindra/newview/llmediactrl.h3
-rwxr-xr-xindra/newview/llmediadataclient.cpp26
-rwxr-xr-xindra/newview/llmediadataclient.h8
-rwxr-xr-xindra/newview/llmeshrepository.cpp426
-rwxr-xr-xindra/newview/llmeshrepository.h55
-rwxr-xr-xindra/newview/llmoveview.cpp10
-rwxr-xr-xindra/newview/llnamelistctrl.cpp15
-rwxr-xr-xindra/newview/llnamelistctrl.h17
-rwxr-xr-xindra/newview/llnotificationhandler.h16
-rw-r--r--indra/newview/llnotificationlistitem.cpp645
-rw-r--r--indra/newview/llnotificationlistitem.h250
-rw-r--r--[-rwxr-xr-x]indra/newview/llnotificationlistview.cpp (renamed from indra/newview/lltexturestatsuploader.cpp)35
-rw-r--r--[-rwxr-xr-x]indra/newview/llnotificationlistview.h (renamed from indra/newview/lltexturestatsuploader.h)33
-rwxr-xr-xindra/newview/llnotificationmanager.cpp7
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp3
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp6
-rw-r--r--indra/newview/llpanelexperiencelisteditor.h3
-rw-r--r--indra/newview/llpanelexperiencelog.cpp4
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp108
-rw-r--r--indra/newview/llpanelexperiencepicker.h3
-rwxr-xr-xindra/newview/llpanelface.h2
-rwxr-xr-xindra/newview/llpanelgroup.cpp4
-rw-r--r--indra/newview/llpanelgroupexperiences.cpp57
-rw-r--r--indra/newview/llpanelgroupexperiences.h3
-rwxr-xr-xindra/newview/llpanelgroupgeneral.cpp5
-rwxr-xr-xindra/newview/llpanelgroupinvite.cpp92
-rwxr-xr-xindra/newview/llpanelgrouproles.cpp136
-rwxr-xr-xindra/newview/llpanelgrouproles.h3
-rwxr-xr-xindra/newview/llpanellandmarkinfo.cpp1
-rwxr-xr-xindra/newview/llpanellogin.cpp16
-rwxr-xr-xindra/newview/llpanelmaininventory.cpp2
-rwxr-xr-xindra/newview/llpanelmediasettingsgeneral.cpp4
-rwxr-xr-xindra/newview/llpanelobject.cpp11
-rwxr-xr-xindra/newview/llpanelpeople.cpp18
-rwxr-xr-xindra/newview/llpanelpeople.h1
-rwxr-xr-xindra/newview/llpanelpicks.cpp2
-rwxr-xr-xindra/newview/llpanelplaces.cpp16
-rwxr-xr-xindra/newview/llpaneltopinfobar.cpp5
-rwxr-xr-xindra/newview/llpathfindingmanager.cpp18
-rwxr-xr-xindra/newview/llpreviewscript.cpp22
-rwxr-xr-xindra/newview/llpreviewtexture.cpp1
-rwxr-xr-xindra/newview/llproductinforequest.cpp2
-rwxr-xr-xindra/newview/llprogressview.cpp4
-rwxr-xr-xindra/newview/llremoteparcelrequest.cpp2
-rwxr-xr-xindra/newview/llsecapi.cpp41
-rwxr-xr-xindra/newview/llsecapi.h3
-rwxr-xr-xindra/newview/llselectmgr.cpp27
-rwxr-xr-xindra/newview/llsidepanelinventory.cpp1
-rwxr-xr-xindra/newview/llsidepaneliteminfo.cpp5
-rwxr-xr-xindra/newview/llsidepaneltaskinfo.cpp24
-rwxr-xr-xindra/newview/llslurl.cpp7
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp109
-rw-r--r--indra/newview/llsnapshotlivepreview.h2
-rwxr-xr-xindra/newview/llspeakers.cpp19
-rwxr-xr-xindra/newview/llstartup.cpp56
-rw-r--r--indra/newview/llsyntaxid.cpp2
-rwxr-xr-xindra/newview/llsyswellwindow.cpp152
-rwxr-xr-xindra/newview/llsyswellwindow.h51
-rwxr-xr-xindra/newview/lltexturecache.cpp9
-rwxr-xr-xindra/newview/lltexturefetch.cpp57
-rwxr-xr-xindra/newview/lltexturefetch.h1
-rwxr-xr-xindra/newview/lltexturestats.cpp14
-rwxr-xr-xindra/newview/lltoastgroupnotifypanel.cpp2
-rwxr-xr-xindra/newview/lltooldraganddrop.cpp18
-rwxr-xr-xindra/newview/lltranslate.cpp409
-rwxr-xr-xindra/newview/lltranslate.h217
-rw-r--r--indra/newview/lltwitterconnect.cpp28
-rwxr-xr-xindra/newview/lluploadfloaterobservers.h1
-rwxr-xr-xindra/newview/llurllineeditorctrl.cpp2
-rw-r--r--indra/newview/llviewerassetupload.cpp16
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp6
-rw-r--r--indra/newview/llviewerfoldertype.cpp2
-rwxr-xr-xindra/newview/llviewerinventory.cpp2
-rwxr-xr-xindra/newview/llviewermedia.cpp65
-rwxr-xr-xindra/newview/llviewermedia.h1
-rwxr-xr-xindra/newview/llviewermenu.cpp66
-rwxr-xr-xindra/newview/llviewermenufile.cpp1
-rwxr-xr-xindra/newview/llviewermessage.cpp119
-rwxr-xr-xindra/newview/llviewerobject.cpp32
-rwxr-xr-xindra/newview/llviewerobject.h2
-rwxr-xr-xindra/newview/llviewerobjectlist.cpp73
-rwxr-xr-xindra/newview/llviewerobjectlist.h10
-rwxr-xr-xindra/newview/llviewerregion.cpp21
-rwxr-xr-xindra/newview/llviewerstats.cpp5
-rwxr-xr-xindra/newview/llvoavatar.cpp22
-rwxr-xr-xindra/newview/llvoavatar.h2
-rwxr-xr-xindra/newview/llvoavatarself.cpp2
-rwxr-xr-xindra/newview/llvoicechannel.cpp2
-rwxr-xr-xindra/newview/llvoicevivox.cpp4
-rwxr-xr-xindra/newview/llvovolume.cpp165
-rwxr-xr-xindra/newview/llvovolume.h6
-rwxr-xr-xindra/newview/llwebprofile.cpp6
-rwxr-xr-xindra/newview/llwlhandlers.cpp6
-rwxr-xr-xindra/newview/llworldmap.cpp1
-rwxr-xr-xindra/newview/llxmlrpctransaction.cpp6
-rwxr-xr-xindra/newview/pipeline.cpp1
-rwxr-xr-xindra/newview/skins/default/colors.xml7
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Large.pngbin0 -> 4182 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Small.pngbin0 -> 3774 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Condense.pngbin0 -> 262 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Expand.pngbin0 -> 239 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Large.pngbin0 -> 1804 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Small.pngbin0 -> 661 bytes
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml5
-rwxr-xr-xindra/newview/skins/default/xui/da/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/da/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/de/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/de/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about_land.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_bumps.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_experiences.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_model_preview.xml38
-rw-r--r--indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml154
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_sys_well.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_inventory.xml16
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_login.xml6
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_email.xml21
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml19
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml120
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_list_editor.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_main_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification_list_item.xml144
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_people.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_advanced.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_setup.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/notification_list_view.xml18
-rwxr-xr-xindra/newview/skins/default/xui/es/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/es/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/fr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/panel_login.xml3
-rwxr-xr-xindra/newview/skins/default/xui/it/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/it/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ja/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ja/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pl/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/pl/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pt/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/pt/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ru/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ru/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/tr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/tr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/zh/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/zh/notifications.xml3
-rwxr-xr-xindra/newview/tests/llhttpretrypolicy_test.cpp6
-rwxr-xr-xindra/newview/tests/lltranslate_test.cpp340
-rwxr-xr-xindra/test/io.cpp421
-rwxr-xr-xindra/test/message_tut.cpp2
-rwxr-xr-xindra/viewer_components/login/lllogin.cpp246
-rwxr-xr-xindra/viewer_components/login/tests/lllogin_test.cpp191
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.cpp2
-rwxr-xr-xindra/viewer_components/updater/llupdatedownloader.cpp54
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.cpp56
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.h1
392 files changed, 13236 insertions, 19694 deletions
diff --git a/indra/cmake/00-COMPILE-LINK-RUN.txt b/indra/cmake/00-COMPILE-LINK-RUN.txt
index 49b899c50d..162b22865c 100644
--- a/indra/cmake/00-COMPILE-LINK-RUN.txt
+++ b/indra/cmake/00-COMPILE-LINK-RUN.txt
@@ -51,7 +51,6 @@ Compilation
WINVER=0x0501 " "
_WIN32_WINNT=0x0501 " "
LL_OS_DRAGDROP_ENABLED=1 " "
- CARES_STATICLIB " "
LIB_NDOF=1 " "
----------------------------------------------------------------------------
@@ -109,7 +108,6 @@ Compilation
DEBUG_INFO=1
LL_DARWIN=1 " "
LL_OS_DRAGDROP_ENABLED=1 " "
- CARES_STATICLIB " "
LIB_NDOF=1 " "
----------------------------------------------------------------------------
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 7a320ffc59..1a3b6c5117 100755
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -191,7 +191,7 @@ if (DARWIN)
add_definitions(-DLL_DARWIN=1)
set(CMAKE_CXX_LINK_FLAGS "-Wl,-no_compact_unwind -Wl,-headerpad_max_install_names,-search_paths_first")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
- set(DARWIN_extra_cstar_flags "-g")
+ set(DARWIN_extra_cstar_flags "-g -Wno-unused-local-typedef -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}")
# NOTE: it's critical that the optimization flag is put in front.
diff --git a/indra/cmake/CARes.cmake b/indra/cmake/CARes.cmake
deleted file mode 100755
index baa55aa49d..0000000000
--- a/indra/cmake/CARes.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- cmake -*-
-include(Linking)
-include(Prebuilt)
-
-set(CARES_FIND_QUIETLY ON)
-set(CARES_FIND_REQUIRED ON)
-
-if (USESYSTEMLIBS)
- include(FindCARes)
-else (USESYSTEMLIBS)
- use_prebuilt_binary(ares)
- add_definitions("-DCARES_STATICLIB")
- if (WINDOWS)
- set(CARES_LIBRARIES areslib)
- elseif (DARWIN)
- set(CARES_LIBRARIES cares)
- else (WINDOWS)
- set(CARES_LIBRARIES cares)
- endif (WINDOWS)
- set(CARES_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/ares)
-endif (USESYSTEMLIBS)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 40d7af8aab..d700c7fd99 100755
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -13,7 +13,6 @@ set(cmake_SOURCE_FILES
BerkeleyDB.cmake
Boost.cmake
BuildVersion.cmake
- CARes.cmake
CMakeCopyIfDifferent.cmake
ConfigurePkgConfig.cmake
CURL.cmake
@@ -27,7 +26,6 @@ set(cmake_SOURCE_FILES
FindAPR.cmake
FindAutobuild.cmake
FindBerkeleyDB.cmake
- FindCARes.cmake
FindFMODEX.cmake
FindGLH.cmake
FindGoogleBreakpad.cmake
diff --git a/indra/cmake/FindCARes.cmake b/indra/cmake/FindCARes.cmake
deleted file mode 100755
index 1ed5b32913..0000000000
--- a/indra/cmake/FindCARes.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- cmake -*-
-
-# - Find c-ares
-# Find the c-ares includes and library
-# This module defines
-# CARES_INCLUDE_DIR, where to find ares.h, etc.
-# CARES_LIBRARIES, the libraries needed to use c-ares.
-# CARES_FOUND, If false, do not try to use c-ares.
-# also defined, but not for general use are
-# CARES_LIBRARY, where to find the c-ares library.
-
-FIND_PATH(CARES_INCLUDE_DIR ares.h
-/usr/local/include
-/usr/include
-)
-
-SET(CARES_NAMES ${CARES_NAMES} cares)
-FIND_LIBRARY(CARES_LIBRARY
- NAMES ${CARES_NAMES}
- PATHS /usr/lib /usr/local/lib
- )
-
-IF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
- SET(CARES_LIBRARIES ${CARES_LIBRARY})
- SET(CARES_FOUND "YES")
-ELSE (CARES_LIBRARY AND CARES_INCLUDE_DIR)
- SET(CARES_FOUND "NO")
-ENDIF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
-
-
-IF (CARES_FOUND)
- IF (NOT CARES_FIND_QUIETLY)
- MESSAGE(STATUS "Found c-ares: ${CARES_LIBRARIES}")
- ENDIF (NOT CARES_FIND_QUIETLY)
-ELSE (CARES_FOUND)
- IF (CARES_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find c-ares library")
- ENDIF (CARES_FIND_REQUIRED)
-ENDIF (CARES_FOUND)
-
-# Deprecated declarations.
-SET (NATIVE_CARES_INCLUDE_PATH ${CARES_INCLUDE_DIR} )
-GET_FILENAME_COMPONENT (NATIVE_CARES_LIB_PATH ${CARES_LIBRARY} PATH)
-
-MARK_AS_ADVANCED(
- CARES_LIBRARY
- CARES_INCLUDE_DIR
- )
diff --git a/indra/cmake/LLCoreHttp.cmake b/indra/cmake/LLCoreHttp.cmake
index cc2e32e8b1..379ae207de 100755
--- a/indra/cmake/LLCoreHttp.cmake
+++ b/indra/cmake/LLCoreHttp.cmake
@@ -1,13 +1,11 @@
# -*- cmake -*-
-include(CARes)
include(CURL)
include(OpenSSL)
include(Boost)
set(LLCOREHTTP_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcorehttp
- ${CARES_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
${BOOST_INCLUDE_DIRS}
diff --git a/indra/cmake/LLMessage.cmake b/indra/cmake/LLMessage.cmake
index 0143d04fd7..7be53ec0ec 100755
--- a/indra/cmake/LLMessage.cmake
+++ b/indra/cmake/LLMessage.cmake
@@ -1,13 +1,11 @@
# -*- cmake -*-
-include(CARes)
include(CURL)
include(OpenSSL)
include(XmlRpcEpi)
set(LLMESSAGE_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llmessage
- ${CARES_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 76d92d7a48..2fb47c58a7 100755
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -130,10 +130,10 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
- # now we only support Xcode 6.0 using 10.9 (Mavericks), minimum OS 10.7 (Lion)
- set(XCODE_VERSION 6.0)
+ # now we only support Xcode 7.0 using 10.11 (El Capitan), minimum OS 10.7 (Lion)
+ set(XCODE_VERSION 7.0)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
- set(CMAKE_OSX_SYSROOT macosx10.9)
+ set(CMAKE_OSX_SYSROOT macosx10.11)
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL 3)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index e529cea29c..8ae487354a 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -39,6 +39,7 @@ set(llcommon_SOURCE_FILES
llbase32.cpp
llbase64.cpp
llbitpack.cpp
+ llcallbacklist.cpp
llcommon.cpp
llcommonutils.cpp
llcoros.cpp
@@ -132,6 +133,7 @@ set(llcommon_HEADER_FILES
llbase64.h
llbitpack.h
llboost.h
+ llcallbacklist.h
llcommon.h
llcommonutils.h
llcoros.h
diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp
new file mode 100644
index 0000000000..541ff75ee4
--- /dev/null
+++ b/indra/llcommon/llcallbacklist.cpp
@@ -0,0 +1,230 @@
+/**
+ * @file llcallbacklist.cpp
+ * @brief A simple list of callback functions to call.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llcallbacklist.h"
+#include "lleventtimer.h"
+#include "llerrorlegacy.h"
+
+// Globals
+//
+LLCallbackList gIdleCallbacks;
+
+//
+// Member functions
+//
+
+LLCallbackList::LLCallbackList()
+{
+ // nothing
+}
+
+LLCallbackList::~LLCallbackList()
+{
+}
+
+
+void LLCallbackList::addFunction( callback_t func, void *data)
+{
+ if (!func)
+ {
+ return;
+ }
+
+ // only add one callback per func/data pair
+ //
+ if (containsFunction(func))
+ {
+ return;
+ }
+
+ callback_pair_t t(func, data);
+ mCallbackList.push_back(t);
+}
+
+bool LLCallbackList::containsFunction( callback_t func, void *data)
+{
+ callback_pair_t t(func, data);
+ callback_list_t::iterator iter = find(func,data);
+ if (iter != mCallbackList.end())
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+bool LLCallbackList::deleteFunction( callback_t func, void *data)
+{
+ callback_list_t::iterator iter = find(func,data);
+ if (iter != mCallbackList.end())
+ {
+ mCallbackList.erase(iter);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+inline
+LLCallbackList::callback_list_t::iterator
+LLCallbackList::find(callback_t func, void *data)
+{
+ callback_pair_t t(func, data);
+ return std::find(mCallbackList.begin(), mCallbackList.end(), t);
+}
+
+void LLCallbackList::deleteAllFunctions()
+{
+ mCallbackList.clear();
+}
+
+
+void LLCallbackList::callFunctions()
+{
+ for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); )
+ {
+ callback_list_t::iterator curiter = iter++;
+ curiter->first(curiter->second);
+ }
+}
+
+// Shim class to allow arbitrary boost::bind
+// expressions to be run as one-time idle callbacks.
+class OnIdleCallbackOneTime
+{
+public:
+ OnIdleCallbackOneTime(nullary_func_t callable):
+ mCallable(callable)
+ {
+ }
+ static void onIdle(void *data)
+ {
+ gIdleCallbacks.deleteFunction(onIdle, data);
+ OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
+ self->call();
+ delete self;
+ }
+ void call()
+ {
+ mCallable();
+ }
+private:
+ nullary_func_t mCallable;
+};
+
+void doOnIdleOneTime(nullary_func_t callable)
+{
+ OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
+ gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
+}
+
+// Shim class to allow generic boost functions to be run as
+// recurring idle callbacks. Callable should return true when done,
+// false to continue getting called.
+class OnIdleCallbackRepeating
+{
+public:
+ OnIdleCallbackRepeating(bool_func_t callable):
+ mCallable(callable)
+ {
+ }
+ // Will keep getting called until the callable returns true.
+ static void onIdle(void *data)
+ {
+ OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
+ bool done = self->call();
+ if (done)
+ {
+ gIdleCallbacks.deleteFunction(onIdle, data);
+ delete self;
+ }
+ }
+ bool call()
+ {
+ return mCallable();
+ }
+private:
+ bool_func_t mCallable;
+};
+
+void doOnIdleRepeating(bool_func_t callable)
+{
+ OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
+ gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
+}
+
+class NullaryFuncEventTimer: public LLEventTimer
+{
+public:
+ NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+
+private:
+ BOOL tick()
+ {
+ mCallable();
+ return TRUE;
+ }
+
+ nullary_func_t mCallable;
+};
+
+// Call a given callable once after specified interval.
+void doAfterInterval(nullary_func_t callable, F32 seconds)
+{
+ new NullaryFuncEventTimer(callable, seconds);
+}
+
+class BoolFuncEventTimer: public LLEventTimer
+{
+public:
+ BoolFuncEventTimer(bool_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+private:
+ BOOL tick()
+ {
+ return mCallable();
+ }
+
+ bool_func_t mCallable;
+};
+
+// Call a given callable every specified number of seconds, until it returns true.
+void doPeriodically(bool_func_t callable, F32 seconds)
+{
+ new BoolFuncEventTimer(callable, seconds);
+}
diff --git a/indra/newview/llcallbacklist.h b/indra/llcommon/llcallbacklist.h
index 0516c9cdb4..89716cd74c 100755..100644
--- a/indra/newview/llcallbacklist.h
+++ b/indra/llcommon/llcallbacklist.h
@@ -28,27 +28,34 @@
#define LL_LLCALLBACKLIST_H
#include "llstl.h"
+#include <boost/function.hpp>
+#include <list>
class LLCallbackList
{
public:
typedef void (*callback_t)(void*);
+
+ typedef std::pair< callback_t,void* > callback_pair_t;
+ // NOTE: It is confirmed that we DEPEND on the order provided by using a list :(
+ //
+ typedef std::list< callback_pair_t > callback_list_t;
LLCallbackList();
~LLCallbackList();
- void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
- BOOL containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
- BOOL deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
- void callFunctions(); // calls all functions
+ void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
+ bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
+ bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
+ void callFunctions(); // calls all functions
void deleteAllFunctions();
static void test();
protected:
- // Use a list so that the callbacks are ordered in case that matters
- typedef std::pair<callback_t,void*> callback_pair_t;
- typedef std::list<callback_pair_t > callback_list_t;
+
+ inline callback_list_t::iterator find(callback_t func, void *data);
+
callback_list_t mCallbackList;
};
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 66cc7cada0..c9bfcacedc 100755
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -45,14 +45,14 @@ namespace
{
/**
- * waitForEventOn() permits a coroutine to temporarily listen on an
+ * suspendUntilEventOn() permits a coroutine to temporarily listen on an
* LLEventPump any number of times. We don't really want to have to ask
* the caller to label each such call with a distinct string; the whole
- * point of waitForEventOn() is to present a nice sequential interface to
+ * point of suspendUntilEventOn() is to present a nice sequential interface to
* the underlying LLEventPump-with-named-listeners machinery. So we'll use
* LLEventPump::inventName() to generate a distinct name for each
* temporary listener. On the other hand, because a given coroutine might
- * call waitForEventOn() any number of times, we don't really want to
+ * call suspendUntilEventOn() any number of times, we don't really want to
* consume an arbitrary number of generated inventName()s: that namespace,
* though large, is nonetheless finite. So we memoize an invented name for
* each distinct coroutine instance.
@@ -73,7 +73,7 @@ std::string listenerNameForCoro()
}
/**
- * Implement behavior described for postAndWait()'s @a replyPumpNamePath
+ * Implement behavior described for postAndSuspend()'s @a replyPumpNamePath
* parameter:
*
* * If <tt>path.isUndefined()</tt>, do nothing.
@@ -145,15 +145,15 @@ void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
} // anonymous
-void llcoro::yield()
+void llcoro::suspend()
{
// By viewer convention, we post an event on the "mainloop" LLEventPump
// each iteration of the main event-handling loop. So waiting for a single
- // event on "mainloop" gives us a one-frame yield.
- waitForEventOn("mainloop");
+ // event on "mainloop" gives us a one-frame suspend.
+ suspendUntilEventOn("mainloop");
}
-LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath)
{
// declare the future
@@ -171,7 +171,7 @@ LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& request
// request event.
LLSD modevent(event);
storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
<< " posting to " << requestPump.getPump().getName()
<< LL_ENDL;
@@ -179,7 +179,7 @@ LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& request
// << ": " << modevent << LL_ENDL;
requestPump.getPump().post(modevent);
}
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
<< " about to wait on LLEventPump " << replyPump.getPump().getName()
<< LL_ENDL;
// trying to dereference ("resolve") the future makes us wait for it
@@ -189,7 +189,7 @@ LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& request
llcoro::Suspending suspended;
value = *future;
} // destroy Suspending as soon as we're back
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
<< " resuming with " << value << LL_ENDL;
// returning should disconnect the connection
return value;
@@ -199,7 +199,7 @@ namespace
{
/**
- * This helper is specifically for the two-pump version of waitForEventOn().
+ * This helper is specifically for the two-pump version of suspendUntilEventOn().
* We use a single future object, but we want to listen on two pumps with it.
* Since we must still adapt from (the callable constructed by)
* boost::dcoroutines::make_callback() (void return) to provide an event
@@ -242,7 +242,7 @@ WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator
namespace llcoro
{
-LLEventWithID postAndWait2(const LLSD& event,
+LLEventWithID postAndSuspend2(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump0,
const LLEventPumpOrPumpName& replyPump1,
@@ -270,12 +270,12 @@ LLEventWithID postAndWait2(const LLSD& event,
replyPump0.getPump().getName());
storeToLLSDPath(modevent, replyPump1NamePath,
replyPump1.getPump().getName());
- LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+ LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name
<< " posting to " << requestPump.getPump().getName()
<< ": " << modevent << LL_ENDL;
requestPump.getPump().post(modevent);
}
- LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+ LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name
<< " about to wait on LLEventPumps " << replyPump0.getPump().getName()
<< ", " << replyPump1.getPump().getName() << LL_ENDL;
// trying to dereference ("resolve") the future makes us wait for it
@@ -285,7 +285,7 @@ LLEventWithID postAndWait2(const LLSD& event,
llcoro::Suspending suspended;
value = *future;
} // destroy Suspending as soon as we're back
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << name
<< " resuming with (" << value.first << ", " << value.second << ")"
<< LL_ENDL;
// returning should disconnect both connections
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
index e2ce4bb193..6fda3d2572 100755
--- a/indra/llcommon/lleventcoro.h
+++ b/indra/llcommon/lleventcoro.h
@@ -106,34 +106,33 @@ VoidListener<LISTENER> voidlistener(const LISTENER& listener)
* runs without suspending for nontrivial time, sprinkle in calls to this
* function to avoid stalling the rest of the viewer processing.
*/
-void yield();
+void suspend();
/**
- * Post specified LLSD event on the specified LLEventPump, then wait for a
+ * Post specified LLSD event on the specified LLEventPump, then suspend for a
* response on specified other LLEventPump. This is more than mere
* convenience: the difference between this function and the sequence
* @code
* requestPump.post(myEvent);
- * LLSD reply = waitForEventOn(replyPump);
+ * LLSD reply = suspendUntilEventOn(replyPump);
* @endcode
* is that the sequence above fails if the reply is posted immediately on
* @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the
* sequence above, the running coroutine isn't even listening on @a replyPump
- * until <tt>requestPump.post()</tt> returns and @c waitForEventOn() is
+ * until <tt>requestPump.post()</tt> returns and @c suspendUntilEventOn() is
* entered. Therefore, the coroutine completely misses an immediate reply
- * event, making it wait indefinitely.
+ * event, making it suspend indefinitely.
*
- * By contrast, postAndWait() listens on the @a replyPump @em before posting
+ * By contrast, postAndSuspend() listens on the @a replyPump @em before posting
* the specified LLSD event on the specified @a requestPump.
*
- * @param self The @c self object passed into a coroutine
* @param event LLSD data to be posted on @a requestPump
* @param requestPump an LLEventPump on which to post @a event. Pass either
* the LLEventPump& or its string name. However, if you pass a
* default-constructed @c LLEventPumpOrPumpName, we skip the post() call.
- * @param replyPump an LLEventPump on which postAndWait() will listen for a
+ * @param replyPump an LLEventPump on which postAndSuspend() will listen for a
* reply. Pass either the LLEventPump& or its string name. The calling
- * coroutine will wait until that reply arrives. (If you're concerned about a
+ * coroutine will suspend until that reply arrives. (If you're concerned about a
* reply that might not arrive, please see also LLEventTimeout.)
* @param replyPumpNamePath specifies the location within @a event in which to
* store <tt>replyPump.getName()</tt>. This is a strictly optional convenience
@@ -156,21 +155,21 @@ void yield();
* @a replyPumpNamePath specifies the entry in the lowest-level structure in
* @a event into which to store <tt>replyPump.getName()</tt>.
*/
-LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD());
/// Wait for the next event on the specified LLEventPump. Pass either the
/// LLEventPump& or its string name.
inline
-LLSD waitForEventOn(const LLEventPumpOrPumpName& pump)
+LLSD suspendUntilEventOn(const LLEventPumpOrPumpName& pump)
{
- // This is now a convenience wrapper for postAndWait().
- return postAndWait(LLSD(), LLEventPumpOrPumpName(), pump);
+ // This is now a convenience wrapper for postAndSuspend().
+ return postAndSuspend(LLSD(), LLEventPumpOrPumpName(), pump);
}
} // namespace llcoro
-/// return type for two-pump variant of waitForEventOn()
+/// return type for two-pump variant of suspendUntilEventOn()
typedef std::pair<LLSD, int> LLEventWithID;
namespace llcoro
@@ -178,7 +177,7 @@ namespace llcoro
/**
* This function waits for a reply on either of two specified LLEventPumps.
- * Otherwise, it closely resembles postAndWait(); please see the documentation
+ * Otherwise, it closely resembles postAndSuspend(); please see the documentation
* for that function for detailed parameter info.
*
* While we could have implemented the single-pump variant in terms of this
@@ -193,19 +192,19 @@ namespace llcoro
* the index of the pump on which it arrived (0 or 1).
*
* @note
- * I'd have preferred to overload the name postAndWait() for both signatures.
+ * I'd have preferred to overload the name postAndSuspend() for both signatures.
* But consider the following ambiguous call:
* @code
- * postAndWait(LLSD(), requestPump, replyPump, "someString");
+ * postAndSuspend(LLSD(), requestPump, replyPump, "someString");
* @endcode
* "someString" could be converted to either LLSD (@a replyPumpNamePath for
* the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump
* function).
*
- * It seems less burdensome to write postAndWait2() than to write either
+ * It seems less burdensome to write postAndSuspend2() than to write either
* LLSD("someString") or LLEventOrPumpName("someString").
*/
-LLEventWithID postAndWait2(const LLSD& event,
+LLEventWithID postAndSuspend2(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump0,
const LLEventPumpOrPumpName& replyPump1,
@@ -217,17 +216,17 @@ LLEventWithID postAndWait2(const LLSD& event,
*/
inline
LLEventWithID
-waitForEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
+suspendUntilEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
{
- // This is now a convenience wrapper for postAndWait2().
- return postAndWait2(LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
+ // This is now a convenience wrapper for postAndSuspend2().
+ return postAndSuspend2(LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
}
/**
- * Helper for the two-pump variant of waitForEventOn(), e.g.:
+ * Helper for the two-pump variant of suspendUntilEventOn(), e.g.:
*
* @code
- * LLSD reply = errorException(waitForEventOn(replyPump, errorPump),
+ * LLSD reply = errorException(suspendUntilEventOn(replyPump, errorPump),
* "error response from login.cgi");
* @endcode
*
@@ -287,7 +286,7 @@ LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc
* 2. Provide its actual name to the event API in question as the name of the
* reply LLEventPump.
* 3. Initiate the request to the event API.
- * 4. Call your LLEventTempStream's wait() method to wait for the reply.
+ * 4. Call your LLEventTempStream's suspend() method to suspend for the reply.
* 5. Let the LLCoroEventPump go out of scope.
*/
class LL_COMMON_API LLCoroEventPump
@@ -305,15 +304,15 @@ public:
/**
* Wait for an event on this LLEventPump.
*/
- LLSD wait()
+ LLSD suspend()
{
- return llcoro::waitForEventOn(mPump);
+ return llcoro::suspendUntilEventOn(mPump);
}
- LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPumpNamePath=LLSD())
{
- return llcoro::postAndWait(event, requestPump, mPump, replyPumpNamePath);
+ return llcoro::postAndSuspend(event, requestPump, mPump, replyPumpNamePath);
}
private:
@@ -349,49 +348,49 @@ public:
/// request pump 1
LLEventPump& getPump1() { return mPump1; }
- /// waitForEventOn(either of our two LLEventPumps)
- LLEventWithID wait()
+ /// suspendUntilEventOn(either of our two LLEventPumps)
+ LLEventWithID suspend()
{
- return llcoro::waitForEventOn(mPump0, mPump1);
+ return llcoro::suspendUntilEventOn(mPump0, mPump1);
}
- /// errorException(wait())
- LLSD waitWithException()
+ /// errorException(suspend())
+ LLSD suspendWithException()
{
- return llcoro::errorException(wait(), std::string("Error event on ") + getName1());
+ return llcoro::errorException(suspend(), std::string("Error event on ") + getName1());
}
- /// errorLog(wait())
- LLSD waitWithLog()
+ /// errorLog(suspend())
+ LLSD suspendWithLog()
{
- return llcoro::errorLog(wait(), std::string("Error event on ") + getName1());
+ return llcoro::errorLog(suspend(), std::string("Error event on ") + getName1());
}
- LLEventWithID postAndWait(const LLSD& event,
+ LLEventWithID postAndSuspend(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::postAndWait2(event, requestPump, mPump0, mPump1,
+ return llcoro::postAndSuspend2(event, requestPump, mPump0, mPump1,
replyPump0NamePath, replyPump1NamePath);
}
- LLSD postAndWaitWithException(const LLSD& event,
+ LLSD postAndSuspendWithException(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::errorException(postAndWait(event, requestPump,
+ return llcoro::errorException(postAndSuspend(event, requestPump,
replyPump0NamePath, replyPump1NamePath),
std::string("Error event on ") + getName1());
}
- LLSD postAndWaitWithLog(const LLSD& event,
+ LLSD postAndSuspendWithLog(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::errorLog(postAndWait(event, requestPump,
+ return llcoro::errorLog(postAndSuspend(event, requestPump,
replyPump0NamePath, replyPump1NamePath),
std::string("Error event on ") + getName1());
}
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index ae11988df8..3a8eabac09 100755
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -2176,8 +2176,7 @@ void* ll_aligned_malloc_fallback( size_t size, int align )
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
- unsigned int for_alloc = sysinfo.dwPageSize;
- while(for_alloc < size) for_alloc += sysinfo.dwPageSize;
+ unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize;
void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
if(NULL == p) {
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index c4c9cc0566..0fb257aab1 100755
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llunits.h"
+#include "stdtypes.h"
#if !LL_WINDOWS
#include <stdint.h>
#endif
@@ -59,7 +60,7 @@ class LLMutex ;
LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
#ifdef SHOW_ASSERT
-#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment))
+#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(uintptr_t(ptr),((U32)alignment))
#else
#define ll_assert_aligned(ptr,alignment)
#endif
@@ -69,13 +70,13 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
{
return reinterpret_cast<T*>(
- (reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
+ (uintptr_t(address) + 0xF) & ~0xF);
}
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
{
return reinterpret_cast<T*>(
- (reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
+ (uintptr_t(address) + 0x3F) & ~0x3F);
}
#if LL_LINUX || LL_DARWIN
@@ -97,7 +98,7 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
- // change preprocessro code to: #if 1 && defined(LL_WINDOWS)
+ // change preprocessor code to: #if 1 && defined(LL_WINDOWS)
#if 0 && defined(LL_WINDOWS)
void* ll_aligned_malloc_fallback( size_t size, int align );
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
index 3659a319a2..ea535cee86 100644
--- a/indra/llcommon/llmutex.h
+++ b/indra/llcommon/llmutex.h
@@ -33,6 +33,10 @@
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
+#if MUTEX_DEBUG
+#include <map>
+#endif
+
struct apr_thread_mutex_t;
struct apr_pool_t;
struct apr_thread_cond_t;
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 715df36f39..44f56daf2d 100755
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -710,7 +710,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// Tie the lifespan of this child process to the lifespan of our APR
// pool: on destruction of the pool, forcibly kill the process. Tell
- // APR to try SIGTERM and wait 3 seconds. If that didn't work, use
+ // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use
// SIGKILL.
apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT);
|*==========================================================================*/
@@ -738,8 +738,11 @@ LLProcess::LLProcess(const LLSDOrParams& params):
{
mPipes.replace(i, new ReadPipeImpl(desc, pipe, FILESLOT(i)));
}
- LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name()
- << "('" << desc << "')" << LL_ENDL;
+ // Removed temporaily for Xcode 7 build tests: error was:
+ // "error: expression with side effects will be evaluated despite
+ // being used as an operand to 'typeid' [-Werror,-Wpotentially-evaluated-expression]""
+ //LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name()
+ // << "('" << desc << "')" << LL_ENDL;
}
}
@@ -986,9 +989,9 @@ void LLProcess::handle_status(int reason, int status)
// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT);
// It's just wrong to call apr_proc_wait() here. The only way APR knows to
// call us with APR_OC_REASON_DEATH is that it's already reaped this child
- // process, so calling wait() will only produce "huh?" from the OS. We
+ // process, so calling suspend() will only produce "huh?" from the OS. We
// must rely on the status param passed in, which unfortunately comes
- // straight from the OS wait() call, which means we have to decode it by
+ // straight from the OS suspend() call, which means we have to decode it by
// hand.
mStatus = interpret_status(status);
LL_INFOS("LLProcess") << getStatusString() << LL_ENDL;
diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp
index 2afdba388a..8caaaee534 100644
--- a/indra/llcommon/llsdjson.cpp
+++ b/indra/llcommon/llsdjson.cpp
@@ -76,3 +76,51 @@ LLSD LlsdFromJson(const Json::Value &val)
}
return result;
}
+
+//=========================================================================
+Json::Value LlsdToJson(const LLSD &val)
+{
+ Json::Value result;
+
+ switch (val.type())
+ {
+ case LLSD::TypeUndefined:
+ result = Json::Value::null;
+ break;
+ case LLSD::TypeBoolean:
+ result = Json::Value(static_cast<bool>(val.asBoolean()));
+ break;
+ case LLSD::TypeInteger:
+ result = Json::Value(static_cast<int>(val.asInteger()));
+ break;
+ case LLSD::TypeReal:
+ result = Json::Value(static_cast<double>(val.asReal()));
+ break;
+ case LLSD::TypeURI:
+ case LLSD::TypeDate:
+ case LLSD::TypeUUID:
+ case LLSD::TypeString:
+ result = Json::Value(val.asString());
+ break;
+ case LLSD::TypeMap:
+ result = Json::Value(Json::objectValue);
+ for (LLSD::map_const_iterator it = val.beginMap(); it != val.endMap(); ++it)
+ {
+ result[it->first] = LlsdToJson(it->second);
+ }
+ break;
+ case LLSD::TypeArray:
+ result = Json::Value(Json::arrayValue);
+ for (LLSD::array_const_iterator it = val.beginArray(); it != val.endArray(); ++it)
+ {
+ result.append(LlsdToJson(*it));
+ }
+ break;
+ case LLSD::TypeBinary:
+ default:
+ LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL;
+ break;
+ }
+
+ return result;
+}
diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h
index cdf9fed500..2be7112404 100644
--- a/indra/llcommon/llsdjson.h
+++ b/indra/llcommon/llsdjson.h
@@ -55,5 +55,23 @@
/// Order is preserved for an array but not for objects.
LLSD LlsdFromJson(const Json::Value &val);
+/// Convert an LLSD object into Parsed JSON object maintaining member names and
+/// array indexs.
+///
+/// Types are converted as follows:
+/// LLSD Type | JSON Type
+/// --------------+----------------
+/// TypeUndefined | null
+/// TypeBoolean | boolean
+/// TypeInteger | integer
+/// TypeReal | real/numeric
+/// TypeString | string
+/// TypeURI | string
+/// TypeDate | string
+/// TypeUUID | string
+/// TypeMap | object
+/// TypeArray | array
+/// TypeBinary | unsupported
+Json::Value LlsdToJson(const LLSD &val);
#endif // LL_LLSDJSON_H
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 02f10fa2ba..0435cb8a08 100755
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -27,6 +27,7 @@
#ifndef LL_LLSTL_H
#define LL_LLSTL_H
+#include "stdtypes.h"
#include <functional>
#include <algorithm>
#include <map>
@@ -272,6 +273,7 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
}
};
+// Useful for replacing the removeObj() functionality of LLDynamicArray
// Example:
// for (std::vector<T>::iterator iter = mList.begin(); iter != mList.end(); )
// {
@@ -530,7 +532,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs)
return strcmp(lhs->name(), rhs->name()) < 0;
#else // not Linux, or gcc 4.4+
// Just use before(), as we normally would
- return lhs->before(*rhs);
+ return lhs->before(*rhs) ? true : false;
#endif
}
diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp
index d98bc297e5..82d0dc8b4b 100644
--- a/indra/llcommon/lluriparser.cpp
+++ b/indra/llcommon/lluriparser.cpp
@@ -238,12 +238,12 @@ void LLUriParser::glueSecond(std::string& uri) const
{
uri += '?';
uri += mQuery;
+ }
- if (mFragment.size())
- {
- uri += '#';
- uri += mFragment;
- }
+ if (mFragment.size())
+ {
+ uri += '#';
+ uri += mFragment;
}
}
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
index 00be5035f2..1ee79e9eb6 100755
--- a/indra/llcommon/tests/lleventcoro_test.cpp
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -129,8 +129,8 @@ typedef coroutine<std::string::iterator(void)> match_coroutine_type;
*****************************************************************************/
/// Simulate an event API whose response is immediate: sent on receipt of the
/// initial request, rather than after some delay. This is the case that
-/// distinguishes postAndWait() from calling post(), then calling
-/// waitForEventOn().
+/// distinguishes postAndSuspend() from calling post(), then calling
+/// suspendUntilEventOn().
class ImmediateAPI
{
public:
@@ -241,13 +241,13 @@ namespace tut
// declare the future
boost::dcoroutines::future<LLSD> future(self);
- // tell the future what to wait for
+ // tell the future what to suspend for
LLTempBoundListener connection(
LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::dcoroutines::make_callback(future))));
ensure("Not yet", ! future);
// attempting to dereference ("resolve") the future causes the calling
- // coroutine to wait for it
- debug("about to wait");
+ // coroutine to suspend for it
+ debug("about to suspend");
result = *future;
ensure("Got it", future);
}
@@ -269,9 +269,9 @@ namespace tut
coro(std::nothrow);
// When the coroutine waits for the event pump, it returns here.
debug("about to send");
- // Satisfy the wait.
+ // Satisfy the suspend.
LLEventPumps::instance().obtain("source").post("received");
- // Now wait for the coroutine to complete.
+ // Now suspend for the coroutine to complete.
ensure("coroutine complete", ! coro);
// ensure the coroutine ran and woke up again with the intended result
ensure_equals(result.asString(), "received");
@@ -281,7 +281,7 @@ namespace tut
{
BEGIN
{
- result = waitForEventOn("source");
+ result = suspendUntilEventOn("source");
}
END
}
@@ -303,7 +303,7 @@ namespace tut
{
BEGIN
{
- LLEventWithID pair = waitForEventOn("reply", "error");
+ LLEventWithID pair = suspendUntilEventOn("reply", "error");
result = pair.first;
which = pair.second;
debug(STRINGIZE("result = " << result << ", which = " << which));
@@ -347,7 +347,7 @@ namespace tut
{
LLCoroEventPump waiter;
replyName = waiter.getName();
- result = waiter.wait();
+ result = waiter.suspend();
}
END
}
@@ -372,7 +372,7 @@ namespace tut
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
- LLEventWithID pair(waiter.wait());
+ LLEventWithID pair(waiter.suspend());
result = pair.first;
which = pair.second;
}
@@ -414,7 +414,7 @@ namespace tut
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
- result = waiter.waitWithException();
+ result = waiter.suspendWithException();
}
END
}
@@ -441,7 +441,7 @@ namespace tut
errorName = waiter.getName1();
try
{
- result = waiter.waitWithException();
+ result = waiter.suspendWithException();
debug("no exception");
}
catch (const LLErrorEvent& e)
@@ -474,7 +474,7 @@ namespace tut
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
- result = waiter.waitWithLog();
+ result = waiter.suspendWithLog();
}
END
}
@@ -502,7 +502,7 @@ namespace tut
WrapLLErrs capture;
try
{
- result = waiter.waitWithLog();
+ result = waiter.suspendWithLog();
debug("no exception");
}
catch (const WrapLLErrs::FatalException& e)
@@ -532,7 +532,7 @@ namespace tut
{
BEGIN
{
- result = postAndWait(LLSDMap("value", 17), // request event
+ result = postAndSuspend(LLSDMap("value", 17), // request event
immediateAPI.getPump(), // requestPump
"reply1", // replyPump
"reply"); // request["reply"] = name
@@ -554,7 +554,7 @@ namespace tut
{
BEGIN
{
- LLEventWithID pair = ::postAndWait2(LLSDMap("value", 18),
+ LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18),
immediateAPI.getPump(),
"reply2",
"error2",
@@ -582,7 +582,7 @@ namespace tut
{
BEGIN
{
- LLEventWithID pair = ::postAndWait2(LLSDMap("value", 18)("fail", LLSD()),
+ LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18)("fail", LLSD()),
immediateAPI.getPump(),
"reply2",
"error2",
@@ -611,7 +611,7 @@ namespace tut
BEGIN
{
LLCoroEventPump waiter;
- result = waiter.postAndWait(LLSDMap("value", 17),
+ result = waiter.postAndSuspend(LLSDMap("value", 17),
immediateAPI.getPump(), "reply");
}
END
@@ -632,7 +632,7 @@ namespace tut
BEGIN
{
LLCoroEventPumps waiter;
- LLEventWithID pair(waiter.postAndWait(LLSDMap("value", 23),
+ LLEventWithID pair(waiter.postAndSuspend(LLSDMap("value", 23),
immediateAPI.getPump(), "reply", "error"));
result = pair.first;
which = pair.second;
@@ -657,7 +657,7 @@ namespace tut
{
LLCoroEventPumps waiter;
LLEventWithID pair(
- waiter.postAndWait(LLSDMap("value", 23)("fail", LLSD()),
+ waiter.postAndSuspend(LLSDMap("value", 23)("fail", LLSD()),
immediateAPI.getPump(), "reply", "error"));
result = pair.first;
which = pair.second;
@@ -681,7 +681,7 @@ namespace tut
BEGIN
{
LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithException(LLSDMap("value", 8),
+ result = waiter.postAndSuspendWithException(LLSDMap("value", 8),
immediateAPI.getPump(), "reply", "error");
}
END
@@ -704,7 +704,7 @@ namespace tut
LLCoroEventPumps waiter;
try
{
- result = waiter.postAndWaitWithException(
+ result = waiter.postAndSuspendWithException(
LLSDMap("value", 9)("fail", LLSD()),
immediateAPI.getPump(), "reply", "error");
debug("no exception");
@@ -734,7 +734,7 @@ namespace tut
BEGIN
{
LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithLog(LLSDMap("value", 30),
+ result = waiter.postAndSuspendWithLog(LLSDMap("value", 30),
immediateAPI.getPump(), "reply", "error");
}
END
@@ -758,7 +758,7 @@ namespace tut
WrapLLErrs capture;
try
{
- result = waiter.postAndWaitWithLog(
+ result = waiter.postAndSuspendWithLog(
LLSDMap("value", 31)("fail", LLSD()),
immediateAPI.getPump(), "reply", "error");
debug("no exception");
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 9631e960c5..4aecf61bd7 100755
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -5,7 +5,6 @@ project(llcorehttp)
include(00-Common)
include(GoogleMock)
include(CURL)
-include(CARes)
include(OpenSSL)
include(ZLIB)
include(LLCoreHttp)
@@ -26,6 +25,7 @@ set(llcorehttp_SOURCE_FILES
bufferarray.cpp
bufferstream.cpp
httpcommon.cpp
+ llhttpconstants.cpp
httpheaders.cpp
httpoptions.cpp
httprequest.cpp
@@ -51,6 +51,7 @@ set(llcorehttp_HEADER_FILES
bufferarray.h
bufferstream.h
httpcommon.h
+ llhttpconstants.h
httphandler.h
httpheaders.h
httpoptions.h
@@ -89,7 +90,6 @@ add_library (llcorehttp ${llcorehttp_SOURCE_FILES})
target_link_libraries(
llcorehttp
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_THREAD_LIBRARY}
@@ -127,7 +127,6 @@ if (LL_TESTS)
${LLCOMMON_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_SYSTEM_LIBRARY}
@@ -159,7 +158,6 @@ if (LL_TESTS)
${LLCOMMON_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_SYSTEM_LIBRARY}
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 17e997688f..4ebe14e740 100755
--- a/indra/llcorehttp/_httplibcurl.cpp
+++ b/indra/llcorehttp/_httplibcurl.cpp
@@ -71,11 +71,10 @@ void HttpLibcurl::shutdown()
{
while (! mActiveOps.empty())
{
- HttpOpRequest * op(* mActiveOps.begin());
+ HttpOpRequest::ptr_t op(* mActiveOps.begin());
mActiveOps.erase(mActiveOps.begin());
cancelRequest(op);
- op->release();
}
if (mMultiHandles)
@@ -204,7 +203,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
// Caller has provided us with a ref count on op.
-void HttpLibcurl::addOp(HttpOpRequest * op)
+void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
{
llassert_always(op->mReqPolicy < mPolicyCount);
llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
@@ -235,21 +234,21 @@ void HttpLibcurl::addOp(HttpOpRequest * op)
HttpPolicy & policy(mService->getPolicy());
LL_INFOS(LOG_CORE) << "TRACE, ToActiveQueue, Handle: "
- << static_cast<HttpHandle>(op)
- << ", Actives: " << mActiveOps.size()
- << ", Readies: " << policy.getReadyCount(op->mReqPolicy)
- << LL_ENDL;
+ << op->getHandle()
+ << ", Actives: " << mActiveOps.size()
+ << ", Readies: " << policy.getReadyCount(op->mReqPolicy)
+ << LL_ENDL;
}
}
// Implements the transport part of any cancel operation.
// See if the handle is an active operation and if so,
-// use the more complicated transport-based cancelation
+// use the more complicated transport-based cancellation
// method to kill the request.
bool HttpLibcurl::cancel(HttpHandle handle)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(handle));
+ HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle);
active_set_t::iterator it(mActiveOps.find(op));
if (mActiveOps.end() == it)
{
@@ -262,7 +261,6 @@ bool HttpLibcurl::cancel(HttpHandle handle)
// Drop references
mActiveOps.erase(it);
--mActiveHandles[op->mReqPolicy];
- op->release();
return true;
}
@@ -273,7 +271,7 @@ bool HttpLibcurl::cancel(HttpHandle handle)
// remove the op from the active list and release the op *after*
// calling this method. It must be called first to deliver the
// op to the reply queue with refcount intact.
-void HttpLibcurl::cancelRequest(HttpOpRequest * op)
+void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
{
// Deactivate request
op->mCurlActive = false;
@@ -287,7 +285,7 @@ void HttpLibcurl::cancelRequest(HttpOpRequest * op)
if (op->mTracing > HTTP_TRACE_OFF)
{
LL_INFOS(LOG_CORE) << "TRACE, RequestCanceled, Handle: "
- << static_cast<HttpHandle>(op)
+ << op->getHandle()
<< ", Status: " << op->mStatus.toTerseString()
<< LL_ENDL;
}
@@ -301,8 +299,11 @@ void HttpLibcurl::cancelRequest(HttpOpRequest * op)
// Keep them synchronized as necessary.
bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status)
{
- HttpOpRequest * op(NULL);
- curl_easy_getinfo(handle, CURLINFO_PRIVATE, &op);
+ HttpHandle ophandle(NULL);
+
+ curl_easy_getinfo(handle, CURLINFO_PRIVATE, &ophandle);
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(ophandle));
+
if (handle != op->mCurlHandle || ! op->mCurlActive)
{
@@ -364,9 +365,9 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode
if (op->mTracing > HTTP_TRACE_OFF)
{
LL_INFOS(LOG_CORE) << "TRACE, RequestComplete, Handle: "
- << static_cast<HttpHandle>(op)
- << ", Status: " << op->mStatus.toTerseString()
- << LL_ENDL;
+ << op->getHandle()
+ << ", Status: " << op->mStatus.toTerseString()
+ << LL_ENDL;
}
// Dispatch to next stage
diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h
index ffc24c63a8..a71eae59c0 100755
--- a/indra/llcorehttp/_httplibcurl.h
+++ b/indra/llcorehttp/_httplibcurl.h
@@ -65,6 +65,8 @@ private:
void operator=(const HttpLibcurl &); // Not defined
public:
+ typedef boost::shared_ptr<HttpOpRequest> opReqPtr_t;
+
/// Give cycles to libcurl to run active requests. Completed
/// operations (successful or failed) will be retried or handed
/// over to the reply queue as final responses.
@@ -80,7 +82,7 @@ public:
/// request. (No additional references will be added.)
///
/// Threading: called by worker thread.
- void addOp(HttpOpRequest * op);
+ void addOp(const opReqPtr_t & op);
/// One-time call to set the number of policy classes to be
/// serviced and to create the resources for each. Value
@@ -148,10 +150,10 @@ protected:
/// Invoked to cancel an active request, mainly during shutdown
/// and destroy.
- void cancelRequest(HttpOpRequest * op);
+ void cancelRequest(const opReqPtr_t &op);
protected:
- typedef std::set<HttpOpRequest *> active_set_t;
+ typedef std::set<opReqPtr_t> active_set_t;
/// Simple request handle cache for libcurl.
///
diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h
index 336dfdc573..86944eb159 100755
--- a/indra/llcorehttp/_httpopcancel.h
+++ b/indra/llcorehttp/_httpopcancel.h
@@ -56,13 +56,8 @@ public:
/// be canceled.
HttpOpCancel(HttpHandle handle);
-protected:
virtual ~HttpOpCancel(); // Use release()
-private:
- HttpOpCancel(const HttpOpCancel &); // Not defined
- void operator=(const HttpOpCancel &); // Not defined
-
public:
virtual void stageFromRequest(HttpService *);
diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp
index fefe561f80..333f20d281 100755
--- a/indra/llcorehttp/_httpoperation.cpp
+++ b/indra/llcorehttp/_httpoperation.cpp
@@ -53,15 +53,18 @@ namespace LLCore
// ==================================
// HttpOperation
// ==================================
-
-
-HttpOperation::HttpOperation()
- : LLCoreInt::RefCounted(true),
- mReplyQueue(NULL),
- mUserHandler(NULL),
- mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
- mReqPriority(0U),
- mTracing(HTTP_TRACE_OFF)
+/*static*/
+HttpOperation::handleMap_t HttpOperation::mHandleMap;
+LLCoreInt::HttpMutex HttpOperation::mOpMutex;
+
+HttpOperation::HttpOperation():
+ boost::enable_shared_from_this<HttpOperation>(),
+ mReplyQueue(),
+ mUserHandler(),
+ mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
+ mReqPriority(0U),
+ mTracing(HTTP_TRACE_OFF),
+ mMyHandle(LLCORE_HTTP_HANDLE_INVALID)
{
mMetricCreated = totalTime();
}
@@ -69,30 +72,17 @@ HttpOperation::HttpOperation()
HttpOperation::~HttpOperation()
{
- setReplyPath(NULL, NULL);
+ destroyHandle();
+ mReplyQueue.reset();
+ mUserHandler.reset();
}
-void HttpOperation::setReplyPath(HttpReplyQueue * reply_queue,
- HttpHandler * user_handler)
+void HttpOperation::setReplyPath(HttpReplyQueue::ptr_t reply_queue,
+ HttpHandler::ptr_t user_handler)
{
- if (reply_queue != mReplyQueue)
- {
- if (mReplyQueue)
- {
- mReplyQueue->release();
- }
-
- if (reply_queue)
- {
- reply_queue->addRef();
- }
-
- mReplyQueue = reply_queue;
- }
-
- // Not refcounted
- mUserHandler = user_handler;
+ mReplyQueue.swap(reply_queue);
+ mUserHandler.swap(user_handler);
}
@@ -134,7 +124,7 @@ void HttpOperation::visitNotifier(HttpRequest *)
HttpResponse * response = new HttpResponse();
response->setStatus(mStatus);
- mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
+ mUserHandler->onCompleted(getHandle(), response);
response->release();
}
@@ -148,20 +138,80 @@ HttpStatus HttpOperation::cancel()
return status;
}
+// Handle methods
+HttpHandle HttpOperation::getHandle()
+{
+ if (mMyHandle == LLCORE_HTTP_HANDLE_INVALID)
+ return createHandle();
+
+ return mMyHandle;
+}
+
+HttpHandle HttpOperation::createHandle()
+{
+ HttpHandle handle = static_cast<HttpHandle>(this);
+
+ {
+ LLCoreInt::HttpScopedLock lock(mOpMutex);
+
+ mHandleMap[handle] = shared_from_this();
+ mMyHandle = handle;
+ }
+
+ return mMyHandle;
+}
+
+void HttpOperation::destroyHandle()
+{
+ if (mMyHandle == LLCORE_HTTP_HANDLE_INVALID)
+ return;
+ {
+ LLCoreInt::HttpScopedLock lock(mOpMutex);
+
+ handleMap_t::iterator it = mHandleMap.find(mMyHandle);
+ if (it != mHandleMap.end())
+ mHandleMap.erase(it);
+ }
+}
+
+/*static*/
+HttpOperation::ptr_t HttpOperation::findByHandle(HttpHandle handle)
+{
+ wptr_t weak;
+
+ {
+ LLCoreInt::HttpScopedLock lock(mOpMutex);
+
+ handleMap_t::iterator it = mHandleMap.find(handle);
+ if (it == mHandleMap.end())
+ {
+ LL_WARNS("LLCore::HTTP") << "Could not find operation for handle " << handle << LL_ENDL;
+ return ptr_t();
+ }
+
+ weak = (*it).second;
+ }
+
+ if (!weak.expired())
+ return weak.lock();
+
+ return ptr_t();
+}
+
void HttpOperation::addAsReply()
{
if (mTracing > HTTP_TRACE_OFF)
{
LL_INFOS(LOG_CORE) << "TRACE, ToReplyQueue, Handle: "
- << static_cast<HttpHandle>(this)
+ << getHandle()
<< LL_ENDL;
}
if (mReplyQueue)
{
- addRef();
- mReplyQueue->addOp(this);
+ HttpOperation::ptr_t op = shared_from_this();
+ mReplyQueue->addOp(op);
}
}
@@ -244,11 +294,8 @@ void HttpOpSpin::stageFromRequest(HttpService * service)
else
{
ms_sleep(1); // backoff interlock plumbing a bit
- this->addRef();
- if (! service->getRequestQueue().addOp(this))
- {
- this->release();
- }
+ HttpOperation::ptr_t opptr = shared_from_this();
+ service->getRequestQueue().addOp(opptr);
}
}
diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h
index 937a61187d..1a75921c09 100755
--- a/indra/llcorehttp/_httpoperation.h
+++ b/indra/llcorehttp/_httpoperation.h
@@ -30,8 +30,7 @@
#include "httpcommon.h"
#include "httprequest.h"
-#include "_refcounted.h"
-
+#include "_mutex.h"
namespace LLCore
{
@@ -69,19 +68,20 @@ class HttpService;
/// via queue-like interfaces that are thread compatible
/// and those interfaces establish the access rules.
-class HttpOperation : public LLCoreInt::RefCounted
+class HttpOperation : private boost::noncopyable,
+ public boost::enable_shared_from_this<HttpOperation>
{
public:
+ typedef boost::shared_ptr<HttpOperation> ptr_t;
+ typedef boost::weak_ptr<HttpOperation> wptr_t;
+ typedef boost::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t;
+
/// Threading: called by consumer thread.
HttpOperation();
-protected:
/// Threading: called by any thread.
virtual ~HttpOperation(); // Use release()
-private:
- HttpOperation(const HttpOperation &); // Not defined
- void operator=(const HttpOperation &); // Not defined
public:
/// Register a reply queue and a handler for completion notifications.
@@ -110,8 +110,8 @@ public:
///
/// Threading: called by consumer thread.
///
- void setReplyPath(HttpReplyQueue * reply_queue,
- HttpHandler * handler);
+ void setReplyPath(HttpReplyQueuePtr_t reply_queue,
+ HttpHandler::ptr_t handler);
/// The three possible staging steps in an operation's lifecycle.
/// Asynchronous requests like HTTP operations move from the
@@ -152,6 +152,18 @@ public:
/// Threading: called by worker thread.
///
virtual HttpStatus cancel();
+
+ /// Retrieves a unique handle for this operation.
+ HttpHandle getHandle();
+
+ template< class OPT >
+ static boost::shared_ptr< OPT > fromHandle(HttpHandle handle)
+ {
+ ptr_t ptr = findByHandle(handle);
+ if (!ptr)
+ return boost::shared_ptr< OPT >();
+ return boost::dynamic_pointer_cast< OPT >(ptr);
+ }
protected:
/// Delivers request to reply queue on completion. After this
@@ -163,8 +175,8 @@ protected:
void addAsReply();
protected:
- HttpReplyQueue * mReplyQueue; // Have refcount
- HttpHandler * mUserHandler; // Naked pointer
+ HttpReplyQueuePtr_t mReplyQueue;
+ HttpHandler::ptr_t mUserHandler;
public:
// Request Data
@@ -177,6 +189,21 @@ public:
// Tracing, debug and metrics
HttpTime mMetricCreated;
int mTracing;
+
+private:
+ typedef std::map<HttpHandle, wptr_t> handleMap_t;
+
+ HttpHandle createHandle();
+ void destroyHandle();
+ HttpHandle mMyHandle;
+
+ static handleMap_t mHandleMap;
+ static LLCoreInt::HttpMutex mOpMutex;
+
+protected:
+ static ptr_t findByHandle(HttpHandle handle);
+
+
}; // end class HttpOperation
@@ -195,7 +222,6 @@ class HttpOpStop : public HttpOperation
public:
HttpOpStop();
-protected:
virtual ~HttpOpStop();
private:
@@ -218,7 +244,6 @@ class HttpOpNull : public HttpOperation
public:
HttpOpNull();
-protected:
virtual ~HttpOpNull();
private:
@@ -241,7 +266,6 @@ public:
// 1 does a soft spin continuously requeuing itself
HttpOpSpin(int mode);
-protected:
virtual ~HttpOpSpin();
private:
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 86110f5b46..557f6207b5 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -187,15 +187,15 @@ HttpOpRequest::~HttpOpRequest()
void HttpOpRequest::stageFromRequest(HttpService * service)
{
- addRef();
- service->getPolicy().addOp(this); // transfers refcount
+ HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
+ service->getPolicy().addOp(self); // transfers refcount
}
void HttpOpRequest::stageFromReady(HttpService * service)
{
- addRef();
- service->getTransport().addOp(this); // transfers refcount
+ HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
+ service->getTransport().addOp(self); // transfers refcount
}
@@ -261,12 +261,19 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setTransferStats(stats);
- mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
+ mUserHandler->onCompleted(this->getHandle(), response);
response->release();
}
}
+// /*static*/
+// HttpOpRequest::ptr_t HttpOpRequest::fromHandle(HttpHandle handle)
+// {
+//
+// return boost::dynamic_pointer_cast<HttpOpRequest>((static_cast<HttpOpRequest *>(handle))->shared_from_this());
+// }
+
HttpStatus HttpOpRequest::cancel()
{
@@ -488,7 +495,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_code(code, CURLOPT_NOPROGRESS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
check_curl_easy_code(code, CURLOPT_URL);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle());
check_curl_easy_code(code, CURLOPT_PRIVATE);
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
@@ -499,15 +506,15 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_code(code, CURLOPT_MAXREDIRS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
check_curl_easy_code(code, CURLOPT_WRITEFUNCTION);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, this);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, getHandle());
check_curl_easy_code(code, CURLOPT_WRITEDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback);
check_curl_easy_code(code, CURLOPT_READFUNCTION);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, getHandle());
check_curl_easy_code(code, CURLOPT_READDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback);
check_curl_easy_code(code, CURLOPT_SEEKFUNCTION);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, this);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle());
check_curl_easy_code(code, CURLOPT_SEEKDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
@@ -517,7 +524,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, getHandle());
check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
mCallbackSSLVerify = gpolicy.mSslCtxCallback;
}
@@ -776,7 +783,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void * userdata)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
if (! op->mReplyBody)
{
@@ -790,7 +797,7 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void
size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
if (! op->mReqBody)
{
@@ -819,7 +826,7 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void
int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
if (!op->mReqBody)
{
@@ -855,7 +862,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
static const char con_ran_line[] = "content-range";
static const char con_retry_line[] = "retry-after";
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
const size_t hdr_size(size * nmemb);
const char * hdr_data(static_cast<const char *>(data)); // Not null terminated
@@ -999,7 +1006,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
if (op->mCallbackSSLVerify)
{
@@ -1016,7 +1023,7 @@ CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userd
int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(param));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param));
if (op->mCallbackSSLVerify)
{
@@ -1028,7 +1035,7 @@ int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
{
- HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+ HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
std::string safe_line;
std::string tag;
@@ -1108,7 +1115,7 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe
if (logit)
{
LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: "
- << static_cast<HttpHandle>(op)
+ << op->getHandle()
<< ", Type: " << tag
<< ", Data: " << safe_line
<< LL_ENDL;
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 1b449a5abc..dbcc57d0fd 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -66,9 +66,10 @@ class BufferArray;
class HttpOpRequest : public HttpOperation
{
public:
+ typedef boost::shared_ptr<HttpOpRequest> ptr_t;
+
HttpOpRequest();
-protected:
virtual ~HttpOpRequest(); // Use release()
private:
diff --git a/indra/llcorehttp/_httpopsetget.h b/indra/llcorehttp/_httpopsetget.h
index a1e76dd429..eabd41e79f 100755
--- a/indra/llcorehttp/_httpopsetget.h
+++ b/indra/llcorehttp/_httpopsetget.h
@@ -53,9 +53,10 @@ namespace LLCore
class HttpOpSetGet : public HttpOperation
{
public:
+ typedef boost::shared_ptr<HttpOpSetGet> ptr_t;
+
HttpOpSetGet();
-protected:
virtual ~HttpOpSetGet(); // Use release()
private:
diff --git a/indra/llcorehttp/_httpopsetpriority.h b/indra/llcorehttp/_httpopsetpriority.h
index 31706b737c..43e2aa081b 100755
--- a/indra/llcorehttp/_httpopsetpriority.h
+++ b/indra/llcorehttp/_httpopsetpriority.h
@@ -51,7 +51,6 @@ class HttpOpSetPriority : public HttpOperation
public:
HttpOpSetPriority(HttpHandle handle, HttpRequest::priority_t priority);
-protected:
virtual ~HttpOpSetPriority();
private:
diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp
index e5d6321401..fd78a5dadc 100755
--- a/indra/llcorehttp/_httppolicy.cpp
+++ b/indra/llcorehttp/_httppolicy.cpp
@@ -116,21 +116,19 @@ void HttpPolicy::shutdown()
HttpRetryQueue & retryq(state.mRetryQueue);
while (! retryq.empty())
{
- HttpOpRequest * op(retryq.top());
+ HttpOpRequest::ptr_t op(retryq.top());
retryq.pop();
op->cancel();
- op->release();
}
HttpReadyQueue & readyq(state.mReadyQueue);
while (! readyq.empty())
{
- HttpOpRequest * op(readyq.top());
+ HttpOpRequest::ptr_t op(readyq.top());
readyq.pop();
op->cancel();
- op->release();
}
}
}
@@ -141,7 +139,7 @@ void HttpPolicy::start()
}
-void HttpPolicy::addOp(HttpOpRequest * op)
+void HttpPolicy::addOp(const HttpOpRequest::ptr_t &op)
{
const int policy_class(op->mReqPolicy);
@@ -151,7 +149,7 @@ void HttpPolicy::addOp(HttpOpRequest * op)
}
-void HttpPolicy::retryOp(HttpOpRequest * op)
+void HttpPolicy::retryOp(const HttpOpRequest::ptr_t &op)
{
static const HttpTime retry_deltas[] =
{
@@ -180,7 +178,7 @@ void HttpPolicy::retryOp(HttpOpRequest * op)
{
++op->mPolicy503Retries;
}
- LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op)
+ LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle()
<< " retry " << op->mPolicyRetries
<< " scheduled in " << (delta / HttpTime(1000))
<< " mS (" << (external_delta ? "external" : "internal")
@@ -189,10 +187,10 @@ void HttpPolicy::retryOp(HttpOpRequest * op)
if (op->mTracing > HTTP_TRACE_OFF)
{
LL_INFOS(LOG_CORE) << "TRACE, ToRetryQueue, Handle: "
- << static_cast<HttpHandle>(op)
- << ", Delta: " << (delta / HttpTime(1000))
- << ", Retries: " << op->mPolicyRetries
- << LL_ENDL;
+ << op->getHandle()
+ << ", Delta: " << (delta / HttpTime(1000))
+ << ", Retries: " << op->mPolicyRetries
+ << LL_ENDL;
}
mClasses[policy_class]->mRetryQueue.push(op);
}
@@ -264,14 +262,14 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
// First see if we have any retries...
while (needed > 0 && ! retryq.empty())
{
- HttpOpRequest * op(retryq.top());
+ HttpOpRequest::ptr_t op(retryq.top());
if (op->mPolicyRetryAt > now)
break;
retryq.pop();
op->stageFromReady(mService);
- op->release();
+ op.reset();
++state.mRequestCount;
--needed;
@@ -296,11 +294,11 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
// Now go on to the new requests...
while (needed > 0 && ! readyq.empty())
{
- HttpOpRequest * op(readyq.top());
+ HttpOpRequest::ptr_t op(readyq.top());
readyq.pop();
op->stageFromReady(mService);
- op->release();
+ op.reset();
++state.mRequestCount;
--needed;
@@ -351,9 +349,9 @@ bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t prior
{
HttpReadyQueue::container_type::iterator cur(iter++);
- if (static_cast<HttpHandle>(*cur) == handle)
+ if ((*cur)->getHandle() == handle)
{
- HttpOpRequest * op(*cur);
+ HttpOpRequest::ptr_t op(*cur);
c.erase(cur); // All iterators are now invalidated
op->mReqPriority = priority;
state.mReadyQueue.push(op); // Re-insert using adapter class
@@ -378,12 +376,11 @@ bool HttpPolicy::cancel(HttpHandle handle)
{
HttpRetryQueue::container_type::iterator cur(iter++);
- if (static_cast<HttpHandle>(*cur) == handle)
+ if ((*cur)->getHandle() == handle)
{
- HttpOpRequest * op(*cur);
+ HttpOpRequest::ptr_t op(*cur);
c1.erase(cur); // All iterators are now invalidated
op->cancel();
- op->release();
return true;
}
}
@@ -394,12 +391,11 @@ bool HttpPolicy::cancel(HttpHandle handle)
{
HttpReadyQueue::container_type::iterator cur(iter++);
- if (static_cast<HttpHandle>(*cur) == handle)
+ if ((*cur)->getHandle() == handle)
{
- HttpOpRequest * op(*cur);
+ HttpOpRequest::ptr_t op(*cur);
c2.erase(cur); // All iterators are now invalidated
op->cancel();
- op->release();
return true;
}
}
@@ -409,7 +405,7 @@ bool HttpPolicy::cancel(HttpHandle handle)
}
-bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
+bool HttpPolicy::stageAfterCompletion(const HttpOpRequest::ptr_t &op)
{
// Retry or finalize
if (! op->mStatus)
@@ -438,7 +434,7 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
// This op is done, finalize it delivering it to the reply queue...
if (! op->mStatus)
{
- LL_WARNS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op)
+ LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle()
<< " failed after " << op->mPolicyRetries
<< " retries. Reason: " << op->mStatus.toString()
<< " (" << op->mStatus.toTerseString() << ")"
@@ -446,13 +442,12 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
}
else if (op->mPolicyRetries)
{
- LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op)
+ LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle()
<< " succeeded on retry " << op->mPolicyRetries << "."
<< LL_ENDL;
}
op->stageFromActive(mService);
- op->release();
return false; // not active
}
diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h
index 11cd89bbd1..3c4126e14b 100755
--- a/indra/llcorehttp/_httppolicy.h
+++ b/indra/llcorehttp/_httppolicy.h
@@ -60,6 +60,8 @@ private:
void operator=(const HttpPolicy &); // Not defined
public:
+ typedef boost::shared_ptr<HttpOpRequest> opReqPtr_t;
+
/// Threading: called by init thread.
HttpRequest::policy_t createPolicyClass();
@@ -96,7 +98,7 @@ public:
/// from queue.
///
/// Threading: called by worker thread
- void addOp(HttpOpRequest *);
+ void addOp(const opReqPtr_t &);
/// Similar to addOp, used when a caller wants to retry a
/// request that has failed. It's placed on a special retry
@@ -106,7 +108,7 @@ public:
/// order.
///
/// Threading: called by worker thread
- void retryOp(HttpOpRequest *);
+ void retryOp(const opReqPtr_t &);
/// Attempt to change the priority of an earlier request.
/// Request that Shadows HttpService's method
@@ -130,7 +132,7 @@ public:
/// sent on to the reply queue.
///
/// Threading: called by worker thread
- bool stageAfterCompletion(HttpOpRequest * op);
+ bool stageAfterCompletion(const opReqPtr_t &op);
/// Get a reference to global policy options. Caller is expected
/// to do context checks like no setting once running. These
diff --git a/indra/llcorehttp/_httpreadyqueue.h b/indra/llcorehttp/_httpreadyqueue.h
index 5f19a9c5f9..7418988ec1 100755
--- a/indra/llcorehttp/_httpreadyqueue.h
+++ b/indra/llcorehttp/_httpreadyqueue.h
@@ -56,12 +56,12 @@ namespace LLCore
#if LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
-typedef std::deque<HttpOpRequest *> HttpReadyQueueBase;
+typedef std::deque<HttpOpRequest::ptr_t> HttpReadyQueueBase;
#else
-typedef std::priority_queue<HttpOpRequest *,
- std::deque<HttpOpRequest *>,
+typedef std::priority_queue<HttpOpRequest::ptr_t,
+ std::deque<HttpOpRequest::ptr_t>,
LLCore::HttpOpRequestCompare> HttpReadyQueueBase;
#endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
diff --git a/indra/llcorehttp/_httpreplyqueue.cpp b/indra/llcorehttp/_httpreplyqueue.cpp
index 558b7bdee9..2b138f3ad5 100755
--- a/indra/llcorehttp/_httpreplyqueue.cpp
+++ b/indra/llcorehttp/_httpreplyqueue.cpp
@@ -39,23 +39,17 @@ namespace LLCore
HttpReplyQueue::HttpReplyQueue()
- : RefCounted(true)
{
}
HttpReplyQueue::~HttpReplyQueue()
{
- while (! mQueue.empty())
- {
- HttpOperation * op = mQueue.back();
- mQueue.pop_back();
- op->release();
- }
+ mQueue.clear();
}
-void HttpReplyQueue::addOp(HttpOperation * op)
+void HttpReplyQueue::addOp(const HttpReplyQueue::opPtr_t &op)
{
{
HttpScopedLock lock(mQueueMutex);
@@ -66,15 +60,15 @@ void HttpReplyQueue::addOp(HttpOperation * op)
}
-HttpOperation * HttpReplyQueue::fetchOp()
+HttpReplyQueue::opPtr_t HttpReplyQueue::fetchOp()
{
- HttpOperation * result(NULL);
+ HttpOperation::ptr_t result;
{
HttpScopedLock lock(mQueueMutex);
if (mQueue.empty())
- return NULL;
+ return opPtr_t();
result = mQueue.front();
mQueue.erase(mQueue.begin());
@@ -98,9 +92,6 @@ void HttpReplyQueue::fetchAll(OpContainer & ops)
mQueue.swap(ops);
}
}
-
- // Caller also acquires the reference counts on each op.
- return;
}
diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h
index 4220a09a3b..0e39e22dde 100755
--- a/indra/llcorehttp/_httpreplyqueue.h
+++ b/indra/llcorehttp/_httpreplyqueue.h
@@ -58,21 +58,19 @@ class HttpOperation;
/// will be coded anyway so it shouldn't be too much of a
/// burden.
-class HttpReplyQueue : public LLCoreInt::RefCounted
+class HttpReplyQueue : private boost::noncopyable
{
-public:
- /// Caller acquires a Refcount on construction
- HttpReplyQueue();
-protected:
- virtual ~HttpReplyQueue(); // Use release()
+public:
+ typedef boost::shared_ptr<HttpOperation> opPtr_t;
+ typedef boost::shared_ptr<HttpReplyQueue> ptr_t;
-private:
- HttpReplyQueue(const HttpReplyQueue &); // Not defined
- void operator=(const HttpReplyQueue &); // Not defined
+ HttpReplyQueue();
+ virtual ~HttpReplyQueue();
public:
- typedef std::vector<HttpOperation *> OpContainer;
+
+ typedef std::vector< opPtr_t > OpContainer;
/// Insert an object at the back of the reply queue.
///
@@ -80,7 +78,7 @@ public:
/// through the queue.
///
/// Threading: callable by any thread.
- void addOp(HttpOperation * op);
+ void addOp(const opPtr_t &op);
/// Fetch an operation from the head of the queue. Returns
/// NULL if none exists.
@@ -88,7 +86,7 @@ public:
/// Caller acquires reference count on returned operation.
///
/// Threading: callable by any thread.
- HttpOperation * fetchOp();
+ opPtr_t fetchOp();
/// Caller acquires reference count on each returned operation
///
@@ -96,6 +94,7 @@ public:
void fetchAll(OpContainer & ops);
protected:
+
OpContainer mQueue;
LLCoreInt::HttpMutex mQueueMutex;
LLCoreInt::HttpConditionVariable mQueueCV;
diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp
index c16966d078..c6f4ad789f 100755
--- a/indra/llcorehttp/_httprequestqueue.cpp
+++ b/indra/llcorehttp/_httprequestqueue.cpp
@@ -47,12 +47,7 @@ HttpRequestQueue::HttpRequestQueue()
HttpRequestQueue::~HttpRequestQueue()
{
- while (! mQueue.empty())
- {
- HttpOperation * op = mQueue.back();
- mQueue.pop_back();
- op->release();
- }
+ mQueue.clear();
}
@@ -73,7 +68,7 @@ void HttpRequestQueue::term()
}
-HttpStatus HttpRequestQueue::addOp(HttpOperation * op)
+HttpStatus HttpRequestQueue::addOp(const HttpRequestQueue::opPtr_t &op)
{
bool wake(false);
{
@@ -95,9 +90,9 @@ HttpStatus HttpRequestQueue::addOp(HttpOperation * op)
}
-HttpOperation * HttpRequestQueue::fetchOp(bool wait)
+HttpRequestQueue::opPtr_t HttpRequestQueue::fetchOp(bool wait)
{
- HttpOperation * result(NULL);
+ HttpOperation::ptr_t result;
{
HttpScopedLock lock(mQueueMutex);
@@ -105,7 +100,7 @@ HttpOperation * HttpRequestQueue::fetchOp(bool wait)
while (mQueue.empty())
{
if (! wait || mQueueStopped)
- return NULL;
+ return HttpOperation::ptr_t();
mQueueCV.wait(lock);
}
diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h
index c9c52b7233..3c3d134b07 100755
--- a/indra/llcorehttp/_httprequestqueue.h
+++ b/indra/llcorehttp/_httprequestqueue.h
@@ -61,6 +61,8 @@ private:
void operator=(const HttpRequestQueue &); // Not defined
public:
+ typedef boost::shared_ptr<HttpOperation> opPtr_t;
+
static void init();
static void term();
@@ -71,7 +73,7 @@ public:
}
public:
- typedef std::vector<HttpOperation *> OpContainer;
+ typedef std::vector<opPtr_t> OpContainer;
/// Insert an object at the back of the request queue.
///
@@ -83,7 +85,7 @@ public:
/// an explicit release() call.
///
/// Threading: callable by any thread.
- HttpStatus addOp(HttpOperation * op);
+ HttpStatus addOp(const opPtr_t &op);
/// Return the operation on the front of the queue. If
/// the queue is empty and @wait is false, call returns
@@ -95,7 +97,7 @@ public:
/// Caller acquires reference count any returned operation
///
/// Threading: callable by any thread.
- HttpOperation * fetchOp(bool wait);
+ opPtr_t fetchOp(bool wait);
/// Return all queued requests to caller. The @ops argument
/// should be empty when called and will be swap()'d with
diff --git a/indra/llcorehttp/_httpretryqueue.h b/indra/llcorehttp/_httpretryqueue.h
index 745adec09d..5d8c529cff 100755
--- a/indra/llcorehttp/_httpretryqueue.h
+++ b/indra/llcorehttp/_httpretryqueue.h
@@ -49,15 +49,15 @@ namespace LLCore
struct HttpOpRetryCompare
{
- bool operator()(const HttpOpRequest * lhs, const HttpOpRequest * rhs)
+ bool operator()(const HttpOpRequest::ptr_t &lhs, const HttpOpRequest::ptr_t &rhs)
{
return lhs->mPolicyRetryAt < rhs->mPolicyRetryAt;
}
};
-typedef std::priority_queue<HttpOpRequest *,
- std::deque<HttpOpRequest *>,
+typedef std::priority_queue<HttpOpRequest::ptr_t,
+ std::deque<HttpOpRequest::ptr_t>,
LLCore::HttpOpRetryCompare> HttpRetryQueueBase;
class HttpRetryQueue : public HttpRetryQueueBase
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index 252db78c89..6c39fdc61b 100755
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -263,14 +263,13 @@ void HttpService::shutdown()
// Cancel requests already on the request queue
HttpRequestQueue::OpContainer ops;
mRequestQueue->fetchAll(false, ops);
- while (! ops.empty())
- {
- HttpOperation * op(ops.front());
- ops.erase(ops.begin());
- op->cancel();
- op->release();
- }
+ for (HttpRequestQueue::OpContainer::iterator it = ops.begin();
+ it != ops.end(); ++it)
+ {
+ (*it)->cancel();
+ }
+ ops.clear();
// Shutdown transport canceling requests, freeing resources
mTransport->shutdown();
@@ -324,7 +323,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
mRequestQueue->fetchAll(wait_for_req, ops);
while (! ops.empty())
{
- HttpOperation * op(ops.front());
+ HttpOperation::ptr_t op(ops.front());
ops.erase(ops.begin());
// Process operation
@@ -338,7 +337,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
if (op->mTracing > HTTP_TRACE_OFF)
{
LL_INFOS(LOG_CORE) << "TRACE, FromRequestQueue, Handle: "
- << static_cast<HttpHandle>(op)
+ << op->getHandle()
<< LL_ENDL;
}
@@ -347,7 +346,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
}
// Done with operation
- op->release();
+ op.reset();
}
// Queue emptied, allow polling loop to sleep
diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp
index 737282c7df..b91aaf0593 100755
--- a/indra/llcorehttp/examples/http_texture_load.cpp
+++ b/indra/llcorehttp/examples/http_texture_load.cpp
@@ -361,7 +361,7 @@ int main(int argc, char** argv)
<< std::endl;
// Clean up
- hr->requestStopThread(NULL);
+ hr->requestStopThread(LLCore::HttpHandler::ptr_t());
ms_sleep(1000);
opt.reset();
delete hr;
@@ -435,6 +435,11 @@ WorkingSet::~WorkingSet()
{
}
+namespace
+{
+ void NoOpDeletor(LLCore::HttpHandler *)
+ { /*NoOp*/ }
+}
bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & opt)
{
@@ -464,11 +469,11 @@ bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & o
LLCore::HttpHandle handle;
if (offset || length)
{
- handle = hr->requestGetByteRange(0, 0, buffer, offset, length, opt, mHeaders, this);
+ handle = hr->requestGetByteRange(0, 0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
}
else
{
- handle = hr->requestGet(0, 0, buffer, opt, mHeaders, this);
+ handle = hr->requestGet(0, 0, buffer, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
}
if (! handle)
{
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 99238ea920..c423047bb0 100755
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -23,12 +23,24 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
+#if LL_WINDOWS
+#define SAFE_SSL 1
+#elif LL_DARWIN
+#define SAFE_SSL 1
+#else
+#define SAFE_SSL 1
+#endif
+#include "linden_common.h" // Modifies curl/curl.h interfaces
#include "httpcommon.h"
-
+#include "llmutex.h"
+#include "llthread.h"
#include <curl/curl.h>
#include <string>
#include <sstream>
+#if SAFE_SSL
+#include <openssl/crypto.h>
+#endif
namespace LLCore
@@ -263,5 +275,168 @@ bool HttpStatus::isRetryable() const
*this == inv_cont_range); // Short data read disagrees with content-range
}
-} // end namespace LLCore
+namespace LLHttp
+{
+namespace
+{
+typedef boost::shared_ptr<LLMutex> LLMutex_ptr;
+std::vector<LLMutex_ptr> sSSLMutex;
+
+CURL *getCurlTemplateHandle()
+{
+ static CURL *curlpTemplateHandle = NULL;
+
+ if (curlpTemplateHandle == NULL)
+ { // Late creation of the template curl handle
+ curlpTemplateHandle = curl_easy_init();
+ if (curlpTemplateHandle == NULL)
+ {
+ LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
+ }
+ else
+ {
+ CURLcode result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ check_curl_code(result, CURLOPT_IPRESOLVE);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOSIGNAL, 1);
+ check_curl_code(result, CURLOPT_NOSIGNAL);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1);
+ check_curl_code(result, CURLOPT_NOPROGRESS);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, "");
+ check_curl_code(result, CURLOPT_ENCODING);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1);
+ check_curl_code(result, CURLOPT_AUTOREFERER);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1);
+ check_curl_code(result, CURLOPT_FOLLOWLOCATION);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_code(result, CURLOPT_SSL_VERIFYPEER);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ check_curl_code(result, CURLOPT_SSL_VERIFYHOST);
+
+ // The Linksys WRT54G V5 router has an issue with frequent
+ // DNS lookups from LAN machines. If they happen too often,
+ // like for every HTTP request, the router gets annoyed after
+ // about 700 or so requests and starts issuing TCP RSTs to
+ // new connections. Reuse the DNS lookups for even a few
+ // seconds and no RSTs.
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
+ check_curl_code(result, CURLOPT_DNS_CACHE_TIMEOUT);
+ }
+ }
+
+ return curlpTemplateHandle;
+}
+
+LLMutex *getCurlMutex()
+{
+ static LLMutex* sHandleMutexp = NULL;
+
+ if (!sHandleMutexp)
+ {
+ sHandleMutexp = new LLMutex(NULL);
+ }
+
+ return sHandleMutexp;
+}
+void deallocateEasyCurl(CURL *curlp)
+{
+ LLMutexLock lock(getCurlMutex());
+
+ curl_easy_cleanup(curlp);
+}
+
+
+#if SAFE_SSL
+//static
+void ssl_locking_callback(int mode, int type, const char *file, int line)
+{
+ if (type >= sSSLMutex.size())
+ {
+ LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL;
+ }
+
+ if (mode & CRYPTO_LOCK)
+ {
+ sSSLMutex[type]->lock();
+ }
+ else
+ {
+ sSSLMutex[type]->unlock();
+ }
+}
+
+//static
+unsigned long ssl_thread_id(void)
+{
+ return LLThread::currentID();
+}
+#endif
+
+
+}
+
+void initialize()
+{
+ // Do not change this "unless you are familiar with and mean to control
+ // internal operations of libcurl"
+ // - http://curl.haxx.se/libcurl/c/curl_global_init.html
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
+
+ check_curl_code(code, CURL_GLOBAL_ALL);
+
+#if SAFE_SSL
+ S32 mutex_count = CRYPTO_num_locks();
+ for (S32 i = 0; i < mutex_count; i++)
+ {
+ sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL)));
+ }
+ CRYPTO_set_id_callback(&ssl_thread_id);
+ CRYPTO_set_locking_callback(&ssl_locking_callback);
+#endif
+
+}
+
+
+void cleanup()
+{
+#if SAFE_SSL
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ sSSLMutex.clear();
+#endif
+
+ curl_global_cleanup();
+}
+
+
+CURL_ptr createEasyHandle()
+{
+ LLMutexLock lock(getCurlMutex());
+
+ CURL* handle = curl_easy_duphandle(getCurlTemplateHandle());
+
+ return CURL_ptr(handle, &deallocateEasyCurl);
+}
+
+std::string getCURLVersion()
+{
+ return std::string(curl_version());
+}
+
+void check_curl_code(CURLcode code, int curl_setopt_option)
+{
+ if (CURLE_OK != code)
+ {
+ // Comment from old llcurl code which may no longer apply:
+ //
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ LL_WARNS() << "libcurl error detected: " << curl_easy_strerror(code)
+ << ", curl_easy_setopt option: " << curl_setopt_option
+ << LL_ENDL;
+ }
+
+}
+
+}
+} // end namespace LLCore
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 898d3d47fa..b2db01d038 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -193,6 +193,7 @@
#include "boost/weak_ptr.hpp"
#include "boost/function.hpp"
#include <string>
+#include <curl/curl.h>
namespace LLCore
{
@@ -208,6 +209,7 @@ namespace LLCore
/// becomes invalid and may be recycled for other queued requests.
typedef void * HttpHandle;
+
#define LLCORE_HTTP_HANDLE_INVALID (NULL)
/// For internal scheduling and metrics, we use a microsecond
@@ -490,6 +492,20 @@ private:
}; // end struct HttpStatus
+/// A namespace for several free methods and low level utilities.
+namespace LLHttp
+{
+ typedef boost::shared_ptr<CURL> CURL_ptr;
+
+ void initialize();
+ void cleanup();
+
+ CURL_ptr createEasyHandle();
+ std::string getCURLVersion();
+
+ void check_curl_code(CURLcode code, int curl_setopt_option);
+}
+
} // end namespace LLCore
#endif // _LLCORE_HTTP_COMMON_H_
diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h
index 7bc9096703..65e043f5d3 100755
--- a/indra/llcorehttp/httphandler.h
+++ b/indra/llcorehttp/httphandler.h
@@ -58,6 +58,9 @@ class HttpResponse;
class HttpHandler
{
public:
+ typedef boost::shared_ptr<HttpHandler> ptr_t;
+ typedef boost::weak_ptr<HttpHandler> wptr_t;
+
virtual ~HttpHandler()
{ }
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 63233259fb..e09f0c3b18 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -55,13 +55,13 @@ namespace LLCore
HttpRequest::HttpRequest()
- : mReplyQueue(NULL),
+ : mReplyQueue(),
mRequestQueue(NULL)
{
mRequestQueue = HttpRequestQueue::instanceOf();
mRequestQueue->addRef();
- mReplyQueue = new HttpReplyQueue();
+ mReplyQueue.reset( new HttpReplyQueue() );
}
@@ -73,11 +73,7 @@ HttpRequest::~HttpRequest()
mRequestQueue = NULL;
}
- if (mReplyQueue)
- {
- mReplyQueue->release();
- mReplyQueue = NULL;
- }
+ mReplyQueue.reset();
}
@@ -128,58 +124,48 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass
}
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
- long value, HttpHandler * handler)
+ long value, HttpHandler::ptr_t handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpSetGet * op = new HttpOpSetGet();
+ HttpOpSetGet::ptr_t op(new HttpOpSetGet());
if (! (status = op->setupSet(opt, pclass, value)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
- const std::string & value, HttpHandler * handler)
+ const std::string & value, HttpHandler::ptr_t handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpSetGet * op = new HttpOpSetGet();
+ HttpOpSetGet::ptr_t op (new HttpOpSetGet());
if (! (status = op->setupSet(opt, pclass, value)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
@@ -199,30 +185,25 @@ HttpHandle HttpRequest::requestGet(policy_t policy_id,
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op(new HttpOpRequest());
if (! (status = op->setupGet(policy_id, priority, url, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
@@ -233,30 +214,25 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
size_t len,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op(new HttpOpRequest());
if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
@@ -266,30 +242,25 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op(new HttpOpRequest());
if (! (status = op->setupPost(policy_id, priority, url, body, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
@@ -299,30 +270,25 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op (new HttpOpRequest());
if (! (status = op->setupPut(policy_id, priority, url, body, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
HttpHandle HttpRequest::requestDelete(policy_t policy_id,
@@ -330,30 +296,25 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id,
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op(new HttpOpRequest());
if (!(status = op->setupDelete(policy_id, priority, url, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (!(status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
HttpHandle HttpRequest::requestPatch(policy_t policy_id,
@@ -362,30 +323,25 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id,
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op (new HttpOpRequest());
if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (!(status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
HttpHandle HttpRequest::requestCopy(policy_t policy_id,
@@ -393,30 +349,26 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op(new HttpOpRequest());
if (!(status = op->setupCopy(policy_id, priority, url, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (!(status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
+ return op->getHandle();
- return handle;
}
HttpHandle HttpRequest::requestMove(policy_t policy_id,
@@ -424,57 +376,48 @@ HttpHandle HttpRequest::requestMove(policy_t policy_id,
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler)
+ HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest::ptr_t op (new HttpOpRequest());
if (!(status = op->setupMove(policy_id, priority, url, options, headers)))
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
op->setReplyPath(mReplyQueue, user_handler);
if (!(status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
-HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
+HttpHandle HttpRequest::requestNoOp(HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpNull * op = new HttpOpNull();
+ HttpOperation::ptr_t op (new HttpOpNull());
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
-
- return handle;
+ return op->getHandle();
}
HttpStatus HttpRequest::update(long usecs)
{
- HttpOperation * op(NULL);
+ HttpOperation::ptr_t op;
if (usecs)
{
@@ -485,7 +428,7 @@ HttpStatus HttpRequest::update(long usecs)
op->visitNotifier(this);
// We're done with the operation
- op->release();
+ op.reset();
}
}
else
@@ -500,13 +443,13 @@ HttpStatus HttpRequest::update(long usecs)
++iter)
{
// Swap op pointer for NULL;
- op = *iter; *iter = NULL;
+ op.reset();
+ op.swap(*iter);
// Process operation
op->visitNotifier(this);
// We're done with the operation
- op->release();
}
}
}
@@ -521,46 +464,38 @@ HttpStatus HttpRequest::update(long usecs)
// Request Management Methods
// ====================================
-HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler * user_handler)
+HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler::ptr_t user_handler)
{
HttpStatus status;
- HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpCancel * op = new HttpOpCancel(request);
+ HttpOperation::ptr_t op(new HttpOpCancel(request));
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return ret_handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- ret_handle = static_cast<HttpHandle>(op);
-
- return ret_handle;
+ return op->getHandle();
}
HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority,
- HttpHandler * handler)
+ HttpHandler::ptr_t handler)
{
HttpStatus status;
- HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpSetPriority * op = new HttpOpSetPriority(request, priority);
+ HttpOperation::ptr_t op (new HttpOpSetPriority(request, priority));
op->setReplyPath(mReplyQueue, handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
- return ret_handle;
+ return LLCORE_HTTP_HANDLE_INVALID;
}
mLastReqStatus = status;
- ret_handle = static_cast<HttpHandle>(op);
-
- return ret_handle;
+ return op->getHandle();
}
@@ -609,22 +544,21 @@ HttpStatus HttpRequest::startThread()
}
-HttpHandle HttpRequest::requestStopThread(HttpHandler * user_handler)
+HttpHandle HttpRequest::requestStopThread(HttpHandler::ptr_t user_handler)
{
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpStop * op = new HttpOpStop();
+ HttpOperation::ptr_t op(new HttpOpStop());
op->setReplyPath(mReplyQueue, user_handler);
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
return handle;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
+ handle = op->getHandle();
return handle;
}
@@ -635,17 +569,16 @@ HttpHandle HttpRequest::requestSpin(int mode)
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpSpin * op = new HttpOpSpin(mode);
- op->setReplyPath(mReplyQueue, NULL);
+ HttpOperation::ptr_t op(new HttpOpSpin(mode));
+ op->setReplyPath(mReplyQueue, HttpHandler::ptr_t());
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
{
- op->release();
mLastReqStatus = status;
return handle;
}
mLastReqStatus = status;
- handle = static_cast<HttpHandle>(op);
+ handle = op->getHandle();
return handle;
}
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 6c2449266f..17cfdcd7b6 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -238,7 +238,7 @@ public:
/// Prototype for policy based callbacks. The callback methods will be executed
/// on the worker thread so no modifications should be made to the HttpHandler object.
- typedef boost::function<HttpStatus(const std::string &, HttpHandler const * const, void *)> policyCallback_t;
+ typedef boost::function<HttpStatus(const std::string &, const HttpHandler::ptr_t &, void *)> policyCallback_t;
/// Set a policy option for a global or class parameter at
/// startup time (prior to thread start).
@@ -270,9 +270,9 @@ public:
/// @return Handle of dynamic request. Use @see getStatus() if
/// the returned handle is invalid.
HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, long value,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
/// @}
@@ -350,7 +350,7 @@ public:
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
/// Queue a full HTTP GET request to be issued with a 'Range' header.
@@ -393,7 +393,7 @@ public:
size_t len,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
/// Queue a full HTTP POST. Query arguments and body may
@@ -434,7 +434,7 @@ public:
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
/// Queue a full HTTP PUT. Query arguments and body may
@@ -475,7 +475,7 @@ public:
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * handler);
+ HttpHandler::ptr_t handler);
/// Queue a full HTTP DELETE. Query arguments and body may
@@ -495,7 +495,7 @@ public:
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler);
+ HttpHandler::ptr_t user_handler);
/// Queue a full HTTP PATCH. Query arguments and body may
/// be provided. Caller is responsible for escaping and
@@ -518,7 +518,7 @@ public:
BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler);
+ HttpHandler::ptr_t user_handler);
/// Queue a full HTTP COPY. Query arguments and body may
/// be provided. Caller is responsible for escaping and
@@ -537,7 +537,7 @@ public:
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler);
+ HttpHandler::ptr_t user_handler);
/// Queue a full HTTP MOVE. Query arguments and body may
/// be provided. Caller is responsible for escaping and
@@ -556,7 +556,7 @@ public:
const std::string & url,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers,
- HttpHandler * user_handler);
+ HttpHandler::ptr_t user_handler);
/// Queue a NoOp request.
/// The request is queued and serviced by the working thread which
@@ -566,7 +566,7 @@ public:
/// @param handler @see requestGet()
/// @return "
///
- HttpHandle requestNoOp(HttpHandler * handler);
+ HttpHandle requestNoOp(HttpHandler::ptr_t handler);
/// While all the heavy work is done by the worker thread, notifications
/// must be performed in the context of the application thread. These
@@ -591,7 +591,7 @@ public:
///
/// @{
- HttpHandle requestCancel(HttpHandle request, HttpHandler *);
+ HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t);
/// Request that a previously-issued request be reprioritized.
/// The status of whether the change itself succeeded arrives
@@ -603,7 +603,7 @@ public:
/// @param handler @see requestGet()
/// @return "
///
- HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler * handler);
+ HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler::ptr_t handler);
/// @}
@@ -641,7 +641,7 @@ public:
/// As the request cannot be cancelled, the handle
/// is generally not useful.
///
- HttpHandle requestStopThread(HttpHandler * handler);
+ HttpHandle requestStopThread(HttpHandler::ptr_t handler);
/// Queue a Spin request.
/// DEBUG/TESTING ONLY. This puts the worker into a CPU spin for
@@ -655,14 +655,15 @@ public:
/// @}
protected:
- void generateNotification(HttpOperation * op);
private:
+ typedef boost::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t;
+
/// @name InstanceData
///
/// @{
HttpStatus mLastReqStatus;
- HttpReplyQueue * mReplyQueue;
+ HttpReplyQueuePtr_t mReplyQueue;
HttpRequestQueue * mRequestQueue;
/// @}
diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llcorehttp/llhttpconstants.cpp
index 32f76f0d70..71d4f19408 100755
--- a/indra/llmessage/llhttpconstants.cpp
+++ b/indra/llcorehttp/llhttpconstants.cpp
@@ -133,94 +133,3 @@ const std::string HTTP_VERB_MOVE("MOVE");
const std::string HTTP_VERB_OPTIONS("OPTIONS");
const std::string HTTP_VERB_PATCH("PATCH");
const std::string HTTP_VERB_COPY("COPY");
-
-const std::string& httpMethodAsVerb(EHTTPMethod method)
-{
- static const std::string VERBS[] =
- {
- HTTP_VERB_INVALID,
- HTTP_VERB_HEAD,
- HTTP_VERB_GET,
- HTTP_VERB_PUT,
- HTTP_VERB_POST,
- HTTP_VERB_DELETE,
- HTTP_VERB_MOVE,
- HTTP_VERB_OPTIONS,
- HTTP_VERB_PATCH,
- HTTP_VERB_COPY
- };
- if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
- {
- return VERBS[0];
- }
- return VERBS[method];
-}
-
-bool isHttpInformationalStatus(S32 status)
-{
- // Check for status 1xx.
- return((100 <= status) && (status < 200));
-}
-
-bool isHttpGoodStatus(S32 status)
-{
- // Check for status 2xx.
- return((200 <= status) && (status < 300));
-}
-
-bool isHttpRedirectStatus(S32 status)
-{
- // Check for status 3xx.
- return((300 <= status) && (status < 400));
-}
-
-bool isHttpClientErrorStatus(S32 status)
-{
- // Status 499 is sometimes used for re-interpreted status 2xx errors
- // based on body content. Treat these as potentially retryable 'server' status errors,
- // since we do not have enough context to know if this will always fail.
- if (HTTP_INTERNAL_ERROR == status) return false;
-
- // Check for status 5xx.
- return((400 <= status) && (status < 500));
-}
-
-bool isHttpServerErrorStatus(S32 status)
-{
- // Status 499 is sometimes used for re-interpreted status 2xx errors.
- // Allow retry of these, since we don't have enough information in this
- // context to know if this will always fail.
- if (HTTP_INTERNAL_ERROR == status) return true;
-
- // Check for status 5xx.
- return((500 <= status) && (status < 600));
-}
-
-// Parses 'Retry-After' header contents and returns seconds until retry should occur.
-bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
-{
- // *TODO: This needs testing! Not in use yet.
- // Examples of Retry-After headers:
- // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
- // Retry-After: 120
-
- // Check for number of seconds version, first:
- char* end = 0;
- // Parse as double
- double seconds = std::strtod(retry_after.c_str(), &end);
- if ( end != 0 && *end == 0 )
- {
- // Successful parse
- seconds_to_wait = (F32) seconds;
- return true;
- }
-
- // Parse rfc1123 date.
- time_t date = curl_getdate(retry_after.c_str(), NULL );
- if (-1 == date) return false;
-
- seconds_to_wait = (F64)date - LLTimer::getTotalSeconds();
-
- return true;
-}
-
diff --git a/indra/llmessage/llhttpconstants.h b/indra/llcorehttp/llhttpconstants.h
index d6bcbd3c19..121448854e 100755
--- a/indra/llmessage/llhttpconstants.h
+++ b/indra/llcorehttp/llhttpconstants.h
@@ -116,13 +116,6 @@ enum EHTTPMethod
HTTP_METHOD_COUNT
};
-const std::string& httpMethodAsVerb(EHTTPMethod method);
-bool isHttpInformationalStatus(S32 status);
-bool isHttpGoodStatus(S32 status);
-bool isHttpRedirectStatus(S32 status);
-bool isHttpClientErrorStatus(S32 status);
-bool isHttpServerErrorStatus(S32 status);
-
// Parses 'Retry-After' header contents and returns seconds until retry should occur.
bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp
index e863ddd13f..bef762f5ce 100755
--- a/indra/llcorehttp/tests/llcorehttp_test.cpp
+++ b/indra/llcorehttp/tests/llcorehttp_test.cpp
@@ -160,7 +160,7 @@ void stop_thread(LLCore::HttpRequest * req)
{
if (req)
{
- req->requestStopThread(NULL);
+ req->requestStopThread(LLCore::HttpHandler::ptr_t());
int count = 0;
int limit = 10;
diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp
index 17b1a96878..e7df2337de 100755
--- a/indra/llcorehttp/tests/test_httpoperation.hpp
+++ b/indra/llcorehttp/tests/test_httpoperation.hpp
@@ -76,12 +76,12 @@ namespace tut
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpOpNull * op = new HttpOpNull();
- ensure(op->getRefCount() == 1);
+ HttpOperation::ptr_t op (new HttpOpNull());
+ ensure(op.use_count() == 1);
ensure(mMemTotal < GetMemTotal());
// release the implicit reference, causing the object to be released
- op->release();
+ op.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -96,26 +96,24 @@ namespace tut
mMemTotal = GetMemTotal();
// Get some handlers
- TestHandler * h1 = new TestHandler();
+ LLCore::HttpHandler::ptr_t h1 (new TestHandler());
// create a new ref counted object with an implicit reference
- HttpOpNull * op = new HttpOpNull();
+ HttpOperation::ptr_t op (new HttpOpNull());
// Add the handlers
- op->setReplyPath(NULL, h1);
+ op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1);
// Check ref count
- ensure(op->getRefCount() == 1);
+ ensure(op.unique() == 1);
// release the reference, releasing the operation but
// not the handlers.
- op->release();
- op = NULL;
+ op.reset();
ensure(mMemTotal != GetMemTotal());
// release the handlers
- delete h1;
- h1 = NULL;
+ h1.reset();
ensure(mMemTotal == GetMemTotal());
}
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index 1f606bd0c1..463e55dd7e 100755
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -247,7 +247,7 @@ void HttpRequestTestObjectType::test<2>()
ensure("Memory being used", mMemTotal < GetMemTotal());
// Issue a NoOp
- HttpHandle handle = req->requestNoOp(NULL);
+ HttpHandle handle = req->requestNoOp(LLCore::HttpHandler::ptr_t());
ensure("Request issued", handle != LLCORE_HTTP_HANDLE_INVALID);
// release the request object
@@ -275,6 +275,10 @@ void HttpRequestTestObjectType::test<2>()
}
}
+namespace
+{
+ void NoOpDeletor(LLCore::HttpHandler *) { }
+}
template <> template <>
void HttpRequestTestObjectType::test<3>()
@@ -287,7 +291,8 @@ void HttpRequestTestObjectType::test<3>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -296,9 +301,8 @@ void HttpRequestTestObjectType::test<3>()
try
{
-
// Get singletons created
- HttpRequest::createService();
+ HttpRequest::createService();
// Start threading early so that thread memory is invariant
// over the test.
@@ -309,7 +313,7 @@ void HttpRequestTestObjectType::test<3>()
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
// Issue a NoOp
- HttpHandle handle = req->requestNoOp(&handler);
+ HttpHandle handle = req->requestNoOp(handlerp);
ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -324,7 +328,7 @@ void HttpRequestTestObjectType::test<3>()
ensure("One handler invocation for request", mHandlerCalls == 1);
// Okay, request a shutdown of the servicing thread
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -378,7 +382,10 @@ void HttpRequestTestObjectType::test<4>()
// references to it after completion of this method.
TestHandler2 handler1(this, "handler1");
TestHandler2 handler2(this, "handler2");
-
+
+ LLCore::HttpHandler::ptr_t handler1p(&handler1, NoOpDeletor);
+ LLCore::HttpHandler::ptr_t handler2p(&handler2, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -388,7 +395,7 @@ void HttpRequestTestObjectType::test<4>()
try
{
-
+
// Get singletons created
HttpRequest::createService();
@@ -402,11 +409,11 @@ void HttpRequestTestObjectType::test<4>()
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
// Issue some NoOps
- HttpHandle handle = req1->requestNoOp(&handler1);
+ HttpHandle handle = req1->requestNoOp(handler1p);
ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
handler1.mExpectHandle = handle;
- handle = req2->requestNoOp(&handler2);
+ handle = req2->requestNoOp(handler2p);
ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
handler2.mExpectHandle = handle;
@@ -423,7 +430,7 @@ void HttpRequestTestObjectType::test<4>()
ensure("One handler invocation for request", mHandlerCalls == 2);
// Okay, request a shutdown of the servicing thread
- handle = req2->requestStopThread(&handler2);
+ handle = req2->requestStopThread(handler2p);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
handler2.mExpectHandle = handle;
@@ -482,7 +489,8 @@ void HttpRequestTestObjectType::test<5>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -491,7 +499,6 @@ void HttpRequestTestObjectType::test<5>()
try
{
-
// Get singletons created
HttpRequest::createService();
@@ -508,7 +515,7 @@ void HttpRequestTestObjectType::test<5>()
ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Issue a NoOp
- handle = req->requestNoOp(&handler);
+ handle = req->requestNoOp(handlerp);
ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -567,7 +574,8 @@ void HttpRequestTestObjectType::test<6>()
try
{
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// Get singletons created
HttpRequest::createService();
@@ -584,7 +592,7 @@ void HttpRequestTestObjectType::test<6>()
ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Issue a NoOp
- handle = req->requestNoOp(&handler);
+ handle = req->requestNoOp(handlerp);
ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -632,7 +640,9 @@ void HttpRequestTestObjectType::test<7>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -642,7 +652,7 @@ void HttpRequestTestObjectType::test<7>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -665,7 +675,7 @@ void HttpRequestTestObjectType::test<7>()
0,
opts,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -681,7 +691,7 @@ void HttpRequestTestObjectType::test<7>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -749,7 +759,8 @@ void HttpRequestTestObjectType::test<8>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -758,7 +769,7 @@ void HttpRequestTestObjectType::test<8>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -776,7 +787,7 @@ void HttpRequestTestObjectType::test<8>()
url_base,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -792,7 +803,7 @@ void HttpRequestTestObjectType::test<8>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -857,7 +868,8 @@ void HttpRequestTestObjectType::test<9>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -866,7 +878,7 @@ void HttpRequestTestObjectType::test<9>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -886,7 +898,7 @@ void HttpRequestTestObjectType::test<9>()
0,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -902,7 +914,7 @@ void HttpRequestTestObjectType::test<9>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -967,7 +979,8 @@ void HttpRequestTestObjectType::test<10>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -977,7 +990,7 @@ void HttpRequestTestObjectType::test<10>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -998,7 +1011,7 @@ void HttpRequestTestObjectType::test<10>()
body,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1014,7 +1027,7 @@ void HttpRequestTestObjectType::test<10>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1085,7 +1098,8 @@ void HttpRequestTestObjectType::test<11>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -1095,7 +1109,7 @@ void HttpRequestTestObjectType::test<11>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -1116,7 +1130,7 @@ void HttpRequestTestObjectType::test<11>()
body,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1132,7 +1146,7 @@ void HttpRequestTestObjectType::test<11>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1204,7 +1218,8 @@ void HttpRequestTestObjectType::test<12>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -1213,7 +1228,7 @@ void HttpRequestTestObjectType::test<12>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Enable tracing
@@ -1236,7 +1251,7 @@ void HttpRequestTestObjectType::test<12>()
0,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1252,7 +1267,7 @@ void HttpRequestTestObjectType::test<12>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1321,7 +1336,8 @@ void HttpRequestTestObjectType::test<13>()
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -1331,7 +1347,7 @@ void HttpRequestTestObjectType::test<13>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Enable tracing
@@ -1360,7 +1376,7 @@ void HttpRequestTestObjectType::test<13>()
0,
opts,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// release options
@@ -1380,7 +1396,7 @@ void HttpRequestTestObjectType::test<13>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1443,7 +1459,8 @@ void HttpRequestTestObjectType::test<14>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
- std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+ std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -1454,7 +1471,7 @@ void HttpRequestTestObjectType::test<14>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -1478,7 +1495,7 @@ void HttpRequestTestObjectType::test<14>()
0,
opts,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1494,7 +1511,7 @@ void HttpRequestTestObjectType::test<14>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1563,6 +1580,7 @@ void HttpRequestTestObjectType::test<15>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// Load and clear the string setting to preload std::string object
// for memory return tests.
@@ -1577,7 +1595,7 @@ void HttpRequestTestObjectType::test<15>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -1596,7 +1614,7 @@ void HttpRequestTestObjectType::test<15>()
url_base,
HttpOptions::ptr_t(),
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1613,7 +1631,7 @@ void HttpRequestTestObjectType::test<15>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
handler.mCheckContentType.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1682,6 +1700,7 @@ void HttpRequestTestObjectType::test<16>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -1693,7 +1712,7 @@ void HttpRequestTestObjectType::test<16>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -1762,7 +1781,7 @@ void HttpRequestTestObjectType::test<16>()
url_base + "reflect/",
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1839,7 +1858,7 @@ void HttpRequestTestObjectType::test<16>()
47,
options,
headers,
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1858,7 +1877,7 @@ void HttpRequestTestObjectType::test<16>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -1923,6 +1942,7 @@ void HttpRequestTestObjectType::test<17>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -1935,7 +1955,7 @@ void HttpRequestTestObjectType::test<17>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -2019,7 +2039,7 @@ void HttpRequestTestObjectType::test<17>()
ba,
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
ba = NULL;
@@ -2040,7 +2060,7 @@ void HttpRequestTestObjectType::test<17>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -2110,6 +2130,7 @@ void HttpRequestTestObjectType::test<18>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -2122,7 +2143,7 @@ void HttpRequestTestObjectType::test<18>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -2207,7 +2228,7 @@ void HttpRequestTestObjectType::test<18>()
ba,
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
ba = NULL;
@@ -2228,7 +2249,7 @@ void HttpRequestTestObjectType::test<18>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -2298,6 +2319,7 @@ void HttpRequestTestObjectType::test<19>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -2309,7 +2331,7 @@ void HttpRequestTestObjectType::test<19>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -2397,7 +2419,7 @@ void HttpRequestTestObjectType::test<19>()
url_base + "reflect/",
options,
headers,
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -2415,7 +2437,7 @@ void HttpRequestTestObjectType::test<19>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -2480,6 +2502,7 @@ void HttpRequestTestObjectType::test<20>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -2492,7 +2515,8 @@ void HttpRequestTestObjectType::test<20>()
try
{
- // Get singletons created
+
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -2596,7 +2620,7 @@ void HttpRequestTestObjectType::test<20>()
ba,
options,
headers,
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
ba = NULL;
@@ -2617,7 +2641,7 @@ void HttpRequestTestObjectType::test<20>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -2686,6 +2710,7 @@ void HttpRequestTestObjectType::test<21>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -2698,7 +2723,7 @@ void HttpRequestTestObjectType::test<21>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -2796,7 +2821,7 @@ void HttpRequestTestObjectType::test<21>()
ba,
options,
headers,
- &handler);
+ handlerp);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
ba = NULL;
@@ -2817,7 +2842,7 @@ void HttpRequestTestObjectType::test<21>()
mStatus = HttpStatus();
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handle = req->requestStopThread(&handler);
+ handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -2882,7 +2907,8 @@ void HttpRequestTestObjectType::test<22>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
-
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
@@ -2892,7 +2918,7 @@ void HttpRequestTestObjectType::test<22>()
try
{
- // options set
+ // options set
options = HttpOptions::ptr_t(new HttpOptions());
options->setRetries(1); // Partial_File is retryable and can timeout in here
@@ -2923,7 +2949,7 @@ void HttpRequestTestObjectType::test<22>()
25,
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -2955,7 +2981,7 @@ void HttpRequestTestObjectType::test<22>()
25,
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -2987,7 +3013,7 @@ void HttpRequestTestObjectType::test<22>()
25,
options,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -3007,7 +3033,7 @@ void HttpRequestTestObjectType::test<22>()
// ======================================
mStatus = HttpStatus();
mHandlerCalls = 0;
- HttpHandle handle = req->requestStopThread(&handler);
+ HttpHandle handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
@@ -3074,7 +3100,8 @@ void HttpRequestTestObjectType::test<23>()
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
TestHandler2 handler(this, "handler");
- std::string url_base(get_base_url() + "/503/"); // path to 503 generators
+ LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor);
+ std::string url_base(get_base_url() + "/503/"); // path to 503 generators
// record the total amount of dynamically allocated memory
mMemTotal = GetMemTotal();
@@ -3085,7 +3112,7 @@ void HttpRequestTestObjectType::test<23>()
try
{
- // Get singletons created
+ // Get singletons created
HttpRequest::createService();
// Start threading early so that thread memory is invariant
@@ -3114,7 +3141,7 @@ void HttpRequestTestObjectType::test<23>()
0,
opts,
HttpHeaders::ptr_t(),
- &handler);
+ handlerp);
std::ostringstream testtag;
testtag << "Valid handle returned for 503 request #" << i;
@@ -3136,7 +3163,7 @@ void HttpRequestTestObjectType::test<23>()
// Okay, request a shutdown of the servicing thread
mStatus = HttpStatus();
mHandlerCalls = 0;
- HttpHandle handle = req->requestStopThread(&handler);
+ HttpHandle handle = req->requestStopThread(handlerp);
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump again
diff --git a/indra/llcorehttp/tests/test_httprequestqueue.hpp b/indra/llcorehttp/tests/test_httprequestqueue.hpp
index 1de2d8f9ab..ef4ce0479b 100755
--- a/indra/llcorehttp/tests/test_httprequestqueue.hpp
+++ b/indra/llcorehttp/tests/test_httprequestqueue.hpp
@@ -113,16 +113,16 @@ void HttpRequestqueueTestObjectType::test<3>()
HttpRequestQueue * rq = HttpRequestQueue::instanceOf();
- HttpOperation * op = new HttpOpNull();
+ HttpOperation::ptr_t op(new HttpOpNull());
rq->addOp(op); // transfer my refcount
op = rq->fetchOp(true); // Potentially hangs the test on failure
- ensure("One goes in, one comes out", NULL != op);
- op->release();
+ ensure("One goes in, one comes out", static_cast<bool>(op));
+ op.reset();
op = rq->fetchOp(false);
- ensure("Better not be two of them", NULL == op);
+ ensure("Better not be two of them", !op);
// release the singleton, hold on to the object
HttpRequestQueue::term();
@@ -144,13 +144,13 @@ void HttpRequestqueueTestObjectType::test<4>()
HttpRequestQueue * rq = HttpRequestQueue::instanceOf();
- HttpOperation * op = new HttpOpNull();
+ HttpOperation::ptr_t op (new HttpOpNull());
rq->addOp(op); // transfer my refcount
- op = new HttpOpNull();
+ op.reset(new HttpOpNull());
rq->addOp(op); // transfer my refcount
- op = new HttpOpNull();
+ op.reset(new HttpOpNull());
rq->addOp(op); // transfer my refcount
{
@@ -159,8 +159,9 @@ void HttpRequestqueueTestObjectType::test<4>()
ensure("Three go in, three come out", 3 == ops.size());
op = rq->fetchOp(false);
- ensure("Better not be any more of them", NULL == op);
-
+ ensure("Better not be any more of them", !op);
+ op.reset();
+
// release the singleton, hold on to the object
HttpRequestQueue::term();
@@ -168,12 +169,13 @@ void HttpRequestqueueTestObjectType::test<4>()
ensure(mMemTotal < GetMemTotal());
// Release them
- while (! ops.empty())
- {
- HttpOperation * op = ops.front();
- ops.erase(ops.begin());
- op->release();
- }
+ ops.clear();
+// while (! ops.empty())
+// {
+// HttpOperation * op = ops.front();
+// ops.erase(ops.begin());
+// op->release();
+// }
}
// Should be clean
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 4caf6dcd05..f240784dc9 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -214,11 +214,13 @@ void LLCrashLogger::gatherFiles()
mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
if(mDebugLog.has("CAFilename"))
{
- LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, mDebugLog["CAFilename"].asString(), NULL);
}
else
{
- LLCurl::setCAFile(gDirUtilp->getCAFile());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
}
LL_INFOS() << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
@@ -227,7 +229,8 @@ void LLCrashLogger::gatherFiles()
else
{
// Figure out the filename of the second life log
- LLCurl::setCAFile(gDirUtilp->getCAFile());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
@@ -407,7 +410,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg
updateApplication(llformat("%s, try %d...", msg.c_str(), i+1));
LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
- host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), new LLCrashLoggerHandler);
+ host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), LLCore::HttpHandler::ptr_t(new LLCrashLoggerHandler));
while(!gBreak)
{
@@ -531,7 +534,7 @@ void LLCrashLogger::updateApplication(const std::string& message)
bool LLCrashLogger::init()
{
- LLCurl::initClass(false);
+ LLCore::LLHttp::initialize();
// We assume that all the logs we're looking for reside on the current drive
gDirUtilp->initAppDirs("SecondLife");
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index 8573fe0d91..a2ce2fee86 100755
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -443,6 +443,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
mBitfieldMask[2] = 0x000000FF;
}
+ if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
S32 src_row_span = getWidth() * 4;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
@@ -476,6 +480,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
S32 src_row_span = getWidth() * 1;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
@@ -501,6 +510,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
S32 src_row_span = getWidth() * 3;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp
index 4eb8dc7440..d0ae105ba7 100755
--- a/indra/llimage/llimagetga.cpp
+++ b/indra/llimage/llimagetga.cpp
@@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
// Origin is the bottom left
U8* dst = raw_image->getData();
U8* src = getData() + mDataOffset;
+
S32 pixels = getWidth() * getHeight();
+
+ if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
if (getComponents() == 4)
{
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index c2198b91a7..8608e45a91 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2536,6 +2536,8 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
U32 cur_influence = 0;
LLVector4 wght(0,0,0,0);
+ U32 joints[4] = {0,0,0,0};
+ LLVector4 joints_with_weights(0,0,0,0);
while (joint != END_INFLUENCES && idx < weights.size())
{
@@ -2543,7 +2545,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
influence |= ((U16) weights[idx++] << 8);
F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
- wght.mV[cur_influence++] = (F32) joint + w;
+ wght.mV[cur_influence] = w;
+ joints[cur_influence] = joint;
+ cur_influence++;
if (cur_influence >= 4)
{
@@ -2554,8 +2558,16 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
joint = weights[idx++];
}
}
-
- face.mWeights[cur_vertex].loadua(wght.mV);
+ F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW];
+ if (wsum <= 0.f)
+ {
+ wght = LLVector4(0.99999f,0.f,0.f,0.f);
+ }
+ for (U32 k=0; k<4; k++)
+ {
+ joints_with_weights[k] = (F32) joints[k] + wght[k];
+ }
+ face.mWeights[cur_vertex].loadua(joints_with_weights.mV);
cur_vertex++;
}
@@ -5584,7 +5596,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
{
resizeVertices(num_vertices+1);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices+3);
}
@@ -5592,7 +5604,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
else
{
resizeVertices(num_vertices);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices);
}
@@ -5714,10 +5726,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LL_CHECK_MEMORY
- if (partial_build)
- {
- return TRUE;
- }
+ //if (partial_build)
+ //{
+ // return TRUE;
+ //}
if (mTypeMask & HOLLOW_MASK)
{
@@ -6072,7 +6084,7 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
if (new_verts > mNumAllocatedVertices)
{
- //double buffer size on expansion
+ // double buffer size on expansion
new_verts *= 2;
S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF;
@@ -6088,18 +6100,21 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
mNormals = mPositions+new_verts;
mTexCoords = (LLVector2*) (mNormals+new_verts);
- //positions
- LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
-
- //normals
- LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
+ if (old_buf != NULL)
+ {
+ // copy old positions into new buffer
+ LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize);
- //tex coords
- LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tc_size);
+ // normals
+ LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_vsize);
- //just clear tangents
- ll_aligned_free_16(mTangents);
- mTangents = NULL;
+ // tex coords
+ LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tc_size);
+ }
+
+ // just clear tangents
+ ll_aligned_free_16(mTangents);
+ mTangents = NULL;
ll_aligned_free<64>(old_buf);
mNumAllocatedVertices = new_verts;
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index c8476f6897..1da2d0c6b1 100755
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -190,8 +190,12 @@ const U8 LL_SCULPT_TYPE_MESH = 5;
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+// for value checks, assign new value after adding new types
+const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH;
+
const U8 LL_SCULPT_FLAG_INVERT = 64;
const U8 LL_SCULPT_FLAG_MIRROR = 128;
+const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR;
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
@@ -968,6 +972,7 @@ protected:
~LLVolume(); // use unref
public:
+ typedef std::vector<LLVolumeFace> face_list_t;
struct FaceParams
{
@@ -1041,6 +1046,10 @@ public:
// conversion if *(LLVolume*) to LLVolume&
const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
+ LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
+
+ face_list_t& getVolumeFaces() { return mVolumeFaces; }
+
U32 mFaceMask; // bit array of which faces exist in this volume
LLVector3 mLODScaleBias; // vector for biasing LOD based on scale
@@ -1080,7 +1089,6 @@ public:
BOOL mGenerateSingleFace;
- typedef std::vector<LLVolumeFace> face_list_t;
face_list_t mVolumeFaces;
public:
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index 6a1b4143cf..d89c482804 100755
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -274,6 +274,19 @@ const LLMatrix4& LLMatrix4::invert(void)
return *this;
}
+// Convenience func for simplifying comparison-heavy code by
+// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f
+//
+void LLMatrix4::condition(void)
+{
+ U32 i;
+ U32 j;
+ for (i = 0; i < 3;i++)
+ for (j = 0; j < 3;j++)
+ mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON)
+ && (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j];
+}
+
LLVector4 LLMatrix4::getFwdRow4() const
{
return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]);
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index a7dce10397..a77c5bc76d 100755
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -180,6 +180,11 @@ public:
const LLMatrix4& setTranslation(const LLVector4 &translation);
const LLMatrix4& setTranslation(const LLVector3 &translation);
+ // Convenience func for simplifying comparison-heavy code by
+ // intentionally stomping values [-FLT_EPS,FLT_EPS] to 0.0
+ //
+ void condition(void);
+
///////////////////////////
//
// Get properties of a matrix
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 12fc1bbcfc..78c84f366a 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -28,8 +28,6 @@ include_directories(
)
set(llmessage_SOURCE_FILES
- llares.cpp
- llareslistener.cpp
llassetstorage.cpp
llavatarname.cpp
llavatarnamecache.cpp
@@ -42,15 +40,11 @@ set(llmessage_SOURCE_FILES
llclassifiedflags.cpp
llcoproceduremanager.cpp
llcorehttputil.cpp
- llcurl.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
- llhttpassetstorage.cpp
- llhttpclient.cpp
- llhttpconstants.cpp
llhttpnode.cpp
llhttpsdhandler.cpp
llinstantmessage.cpp
@@ -78,8 +72,6 @@ set(llmessage_SOURCE_FILES
llsdhttpserver.cpp
llsdmessagebuilder.cpp
llsdmessagereader.cpp
- llsdrpcclient.cpp
- llsdrpcserver.cpp
llservicebuilder.cpp
llservice.cpp
llstoredmessage.cpp
@@ -93,7 +85,6 @@ set(llmessage_SOURCE_FILES
lltransfertargetfile.cpp
lltransfertargetvfile.cpp
lltrustedmessageservice.cpp
- llurlrequest.cpp
lluseroperation.cpp
llxfer.cpp
llxfer_file.cpp
@@ -116,8 +107,6 @@ set(llmessage_SOURCE_FILES
set(llmessage_HEADER_FILES
CMakeLists.txt
- llares.h
- llareslistener.h
llassetstorage.h
llavatarname.h
llavatarnamecache.h
@@ -131,7 +120,6 @@ set(llmessage_HEADER_FILES
llclassifiedflags.h
llcoproceduremanager.h
llcorehttputil.h
- llcurl.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
@@ -141,10 +129,6 @@ set(llmessage_HEADER_FILES
llfiltersd2xmlrpc.h
llfollowcamparams.h
llhost.h
- llhttpassetstorage.h
- llhttpclient.h
- llhttpclientinterface.h
- llhttpconstants.h
llhttpnode.h
llhttpnodeadapter.h
llhttpsdhandler.h
@@ -179,8 +163,6 @@ set(llmessage_HEADER_FILES
llsdhttpserver.h
llsdmessagebuilder.h
llsdmessagereader.h
- llsdrpcclient.h
- llsdrpcserver.h
llservice.h
llservicebuilder.h
llstoredmessage.h
@@ -196,7 +178,6 @@ set(llmessage_HEADER_FILES
lltransfertargetfile.h
lltransfertargetvfile.h
lltrustedmessageservice.h
- llurlrequest.h
lluseroperation.h
llvehicleparams.h
llxfer.h
@@ -228,7 +209,6 @@ target_link_libraries(
${LLCOMMON_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
- ${CARES_LIBRARIES}
${JSONCPP_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
deleted file mode 100755
index 9f90ae1544..0000000000
--- a/indra/llmessage/llares.cpp
+++ /dev/null
@@ -1,839 +0,0 @@
-/**
- * @file llares.cpp
- * @author Bryan O'Sullivan
- * @date 2007-08-15
- * @brief Wrapper for asynchronous DNS lookups.
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llares.h"
-
-#include <ares_dns.h>
-#include <ares_version.h>
-
-#include "apr_portable.h"
-#include "apr_network_io.h"
-#include "apr_poll.h"
-
-#include "llapr.h"
-#include "llareslistener.h"
-
-#if defined(LL_WINDOWS)
-#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
-# define ns_c_in 1
-# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
-# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
-# define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
-#else
-# include <arpa/nameser.h>
-#endif
-
-LLAres::HostResponder::~HostResponder()
-{
-}
-
-void LLAres::HostResponder::hostResult(const hostent *ent)
-{
- LL_INFOS() << "LLAres::HostResponder::hostResult not implemented" << LL_ENDL;
-}
-
-void LLAres::HostResponder::hostError(int code)
-{
- LL_INFOS() << "LLAres::HostResponder::hostError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::NameInfoResponder::~NameInfoResponder()
-{
-}
-
-void LLAres::NameInfoResponder::nameInfoResult(const char *node,
- const char *service)
-{
- LL_INFOS() << "LLAres::NameInfoResponder::nameInfoResult not implemented"
- << LL_ENDL;
-}
-
-void LLAres::NameInfoResponder::nameInfoError(int code)
-{
- LL_INFOS() << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::QueryResponder::~QueryResponder()
-{
-}
-
-void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
-{
- LL_INFOS() << "LLAres::QueryResponder::queryResult not implemented"
- << LL_ENDL;
-}
-
-void LLAres::QueryResponder::queryError(int code)
-{
- LL_INFOS() << "LLAres::QueryResponder::queryError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::LLAres() :
- chan_(NULL),
- mInitSuccess(false)
-{
- if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS ||
- ares_init(&chan_) != ARES_SUCCESS)
- {
- LL_WARNS() << "Could not succesfully initialize ares!" << LL_ENDL;
- return;
- }
-
- mListener = boost::shared_ptr< LLAresListener >(new LLAresListener(this));
-
- mInitSuccess = true;
-}
-
-LLAres::~LLAres()
-{
- ares_destroy(chan_);
- ares_library_cleanup();
-}
-
-void LLAres::cancel()
-{
- ares_cancel(chan_);
-}
-
-static void host_callback_1_5(void *arg, int status, int timeouts,
- struct hostent *ent)
-{
- LLPointer<LLAres::HostResponder> *resp =
- (LLPointer<LLAres::HostResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->hostResult(ent);
- } else {
- (*resp)->hostError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void host_callback(void *arg, int status, struct hostent *ent)
-{
- host_callback_1_5(arg, status, 0, ent);
-}
-#else
-# define host_callback host_callback_1_5
-#endif
-
-void LLAres::getHostByName(const char *name, HostResponder *resp,
- int family)
-{
- ares_gethostbyname(chan_, name, family, host_callback,
- new LLPointer<LLAres::HostResponder>(resp));
-}
-
-void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
-{
- search(name, RES_SRV, resp);
-}
-
-void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
-{
- if (resp && uri.size())
- {
- LLURI* pURI = new LLURI(uri);
-
- resp->mUri = *pURI;
-
- delete pURI;
-
- if (!resp->mUri.scheme().size() || !resp->mUri.hostName().size())
- {
- return;
- }
-
- //LL_INFOS() << "LLAres::rewriteURI (" << uri << ") search: '" << "_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName() << "'" << LL_ENDL;
-
- search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), RES_SRV, resp);
-
-
- }
-}
-
-LLQueryResponder::LLQueryResponder()
- : LLAres::QueryResponder(),
- mResult(ARES_ENODATA),
- mType(RES_INVALID)
-{
-}
-
-int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
- LLPointer<LLDnsRecord> &r)
-{
- std::string rrname;
- size_t enclen;
- int ret;
-
- // RR name.
-
- ret = LLAres::expandName(pos, buf, len, rrname, enclen);
- if (ret != ARES_SUCCESS)
- {
- return ret;
- }
-
- pos += enclen;
-
- if (pos + NS_RRFIXEDSZ > buf + len)
- {
- return ARES_EBADRESP;
- }
-
- int rrtype = DNS_RR_TYPE(pos);
- int rrclass = DNS_RR_CLASS(pos);
- int rrttl = DNS_RR_TTL(pos);
- int rrlen = DNS_RR_LEN(pos);
-
- if (rrclass != ns_c_in)
- {
- return ARES_EBADRESP;
- }
-
- pos += NS_RRFIXEDSZ;
-
- if (pos + rrlen > buf + len)
- {
- return ARES_EBADRESP;
- }
-
- switch (rrtype)
- {
- case RES_A:
- r = new LLARecord(rrname, rrttl);
- break;
- case RES_NS:
- r = new LLNsRecord(rrname, rrttl);
- break;
- case RES_CNAME:
- r = new LLCnameRecord(rrname, rrttl);
- break;
- case RES_PTR:
- r = new LLPtrRecord(rrname, rrttl);
- break;
- case RES_AAAA:
- r = new LLAaaaRecord(rrname, rrttl);
- break;
- case RES_SRV:
- r = new LLSrvRecord(rrname, rrttl);
- break;
- default:
- LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype
- << LL_ENDL;
- return ARES_EBADRESP;
- }
-
- ret = r->parse(buf, len, pos, rrlen);
-
- if (ret == ARES_SUCCESS)
- {
- pos += rrlen;
- } else {
- r = NULL;
- }
-
- return ret;
-}
-
-int LLQueryResponder::parseSection(const char *buf, size_t len,
- size_t count, const char *&pos,
- dns_rrs_t &rrs)
-{
- int ret = ARES_SUCCESS;
-
- for (size_t i = 0; i < count; i++)
- {
- LLPointer<LLDnsRecord> r;
- ret = parseRR(buf, len, pos, r);
- if (ret != ARES_SUCCESS)
- {
- break;
- }
- rrs.push_back(r);
- }
-
- return ret;
-}
-
-void LLQueryResponder::queryResult(const char *buf, size_t len)
-{
- const char *pos = buf;
- int qdcount = DNS_HEADER_QDCOUNT(pos);
- int ancount = DNS_HEADER_ANCOUNT(pos);
- int nscount = DNS_HEADER_NSCOUNT(pos);
- int arcount = DNS_HEADER_ARCOUNT(pos);
- int ret;
-
- if (qdcount == 0 || ancount + nscount + arcount == 0)
- {
- ret = ARES_ENODATA;
- goto bail;
- }
-
- pos += NS_HFIXEDSZ;
-
- for (int i = 0; i < qdcount; i++)
- {
- std::string ignore;
- size_t enclen;
-
- ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
- enclen);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- pos += enclen;
-
- if (i == 0)
- {
- int t = DNS_QUESTION_TYPE(pos);
- switch (t)
- {
- case RES_A:
- case RES_NS:
- case RES_CNAME:
- case RES_PTR:
- case RES_AAAA:
- case RES_SRV:
- mType = (LLResType) t;
- break;
- default:
- LL_INFOS() << "Cannot grok query type " << t << LL_ENDL;
- ret = ARES_EBADQUERY;
- goto bail;
- }
- }
-
- pos += NS_QFIXEDSZ;
- if (pos > buf + len)
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
- }
-
- ret = parseSection(buf, len, ancount, pos, mAnswers);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = parseSection(buf, len, nscount, pos, mAuthorities);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = parseSection(buf, len, arcount, pos, mAdditional);
-
-bail:
- mResult = ret;
- if (mResult == ARES_SUCCESS)
- {
- querySuccess();
- } else {
- queryError(mResult);
- }
-}
-
-void LLQueryResponder::querySuccess()
-{
- LL_INFOS() << "LLQueryResponder::queryResult not implemented" << LL_ENDL;
-}
-
-void LLAres::SrvResponder::querySuccess()
-{
- if (mType == RES_SRV)
- {
- srvResult(mAnswers);
- } else {
- srvError(ARES_EBADRESP);
- }
-}
-
-void LLAres::SrvResponder::queryError(int code)
-{
- srvError(code);
-}
-
-void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
-{
- LL_INFOS() << "LLAres::SrvResponder::srvResult not implemented" << LL_ENDL;
-
- for (size_t i = 0; i < ents.size(); i++)
- {
- const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
-
- LL_INFOS() << "[" << i << "] " << s->host() << ":" << s->port()
- << " priority " << s->priority()
- << " weight " << s->weight()
- << LL_ENDL;
- }
-}
-
-void LLAres::SrvResponder::srvError(int code)
-{
- LL_INFOS() << "LLAres::SrvResponder::srvError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-static void nameinfo_callback_1_5(void *arg, int status, int timeouts,
- char *node, char *service)
-{
- LLPointer<LLAres::NameInfoResponder> *resp =
- (LLPointer<LLAres::NameInfoResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->nameInfoResult(node, service);
- } else {
- (*resp)->nameInfoError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void nameinfo_callback(void *arg, int status, char *node, char *service)
-{
- nameinfo_callback_1_5(arg, status, 0, node, service);
-}
-#else
-# define nameinfo_callback nameinfo_callback_1_5
-#endif
-
-void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
- NameInfoResponder *resp)
-{
- ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
- new LLPointer<NameInfoResponder>(resp));
-}
-
-static void search_callback_1_5(void *arg, int status, int timeouts,
- unsigned char *abuf, int alen)
-{
- LLPointer<LLAres::QueryResponder> *resp =
- (LLPointer<LLAres::QueryResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->queryResult((const char *) abuf, alen);
- } else {
- (*resp)->queryError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void search_callback(void *arg, int status, unsigned char *abuf,
- int alen)
-{
- search_callback_1_5(arg, status, 0, abuf, alen);
-}
-#else
-# define search_callback search_callback_1_5
-#endif
-
-void LLAres::search(const std::string &query, LLResType type,
- QueryResponder *resp)
-{
- ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
- new LLPointer<QueryResponder>(resp));
-}
-
-bool LLAres::process(U64 timeout)
-{
- if (!gAPRPoolp)
- {
- ll_init_apr();
- }
-
- ares_socket_t socks[ARES_GETSOCK_MAXNUM];
- apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
- apr_int32_t nsds = 0;
- int nactive = 0;
- int bitmask;
-
- bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
-
- if (bitmask == 0)
- {
- return nsds > 0;
- }
-
- apr_status_t status;
- LLAPRPool pool;
- status = pool.getStatus() ;
- ll_apr_assert_status(status);
-
- for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
- {
- if (ARES_GETSOCK_READABLE(bitmask, i))
- {
- aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
- }
- else if (ARES_GETSOCK_WRITABLE(bitmask, i))
- {
- aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
- } else {
- continue;
- }
-
- apr_socket_t *aprSock = NULL;
-
- status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
- if (status != APR_SUCCESS)
- {
- ll_apr_warn_status(status);
- return nsds > 0;
- }
-
- aprFds[nactive].desc.s = aprSock;
- aprFds[nactive].desc_type = APR_POLL_SOCKET;
- aprFds[nactive].p = pool.getAPRPool();
- aprFds[nactive].rtnevents = 0;
- aprFds[nactive].client_data = &socks[i];
-
- nactive++;
- }
-
- if (nactive > 0)
- {
- status = apr_poll(aprFds, nactive, &nsds, timeout);
-
- if (status != APR_SUCCESS && status != APR_TIMEUP)
- {
- ll_apr_warn_status(status);
- }
-
- for (int i = 0; i < nactive; i++)
- {
- int evts = aprFds[i].rtnevents;
- int ifd = (evts & (APR_POLLIN | APR_POLLERR))
- ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
- int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
- ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
-
- ares_process_fd(chan_, ifd, ofd);
- }
- }
-
- return nsds > 0;
-}
-
-bool LLAres::processAll()
-{
- bool anyProcessed = false, ret;
-
- do {
- timeval tv;
-
- ret = ares_timeout(chan_, NULL, &tv) != NULL;
-
- if (ret)
- {
- ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
- anyProcessed |= ret;
- }
- } while (ret);
-
- return anyProcessed;
-}
-
-int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s, size_t &enclen)
-{
- char *t;
- int ret;
- long e;
-
- ret = ares_expand_name((const unsigned char *) encoded,
- (const unsigned char *) abuf, alen, &t, &e);
- if (ret == ARES_SUCCESS)
- {
- s.assign(t);
- enclen = e;
- ares_free_string(t);
- }
- return ret;
-}
-
-const char *LLAres::strerror(int code)
-{
- return ares_strerror(code);
-}
-
-LLAres *gAres;
-
-LLAres *ll_init_ares()
-{
- if (gAres == NULL)
- {
- gAres = new LLAres();
- }
- return gAres;
-}
-
-void ll_cleanup_ares()
-{
- if (gAres != NULL)
- {
- delete gAres;
- gAres = NULL;
- }
-}
-
-LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLRefCount(),
- mType(type),
- mName(name),
- mTTL(ttl)
-{
-}
-
-LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLDnsRecord(type, name, ttl)
-{
-}
-
-int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- ret = LLAres::expandName(pos, buf, len, mHost);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_CNAME, name, ttl)
-{
-}
-
-LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_PTR, name, ttl)
-{
-}
-
-LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLDnsRecord(type, name, ttl),
-
- mSize(0)
-{
-}
-
-LLARecord::LLARecord(const std::string &name, unsigned ttl)
- : LLAddrRecord(RES_A, name, ttl)
-{
-}
-
-int LLARecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memset(&mSA, 0, sizeof(mSA));
- memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
- mSA.sin.sin_family = AF_INET6;
- mSize = sizeof(mSA.sin);
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
- : LLAddrRecord(RES_AAAA, name, ttl)
-{
-}
-
-int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen != sizeof(mSA.sin6.sin6_addr))
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memset(&mSA, 0, sizeof(mSA));
- memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
- mSA.sin6.sin6_family = AF_INET6;
- mSize = sizeof(mSA.sin6);
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_SRV, name, ttl),
-
- mPriority(0),
- mWeight(0),
- mPort(0)
-{
-}
-
-int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen < 6)
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memcpy(&mPriority, pos, 2);
- memcpy(&mWeight, pos + 2, 2);
- memcpy(&mPort, pos + 4, 2);
-
- mPriority = ntohs(mPriority);
- mWeight = ntohs(mWeight);
- mPort = ntohs(mPort);
-
- ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
-
-bail:
- return ret;
-}
-
-LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_NS, name, ttl)
-{
-}
-
-void LLAres::UriRewriteResponder::queryError(int code)
-{
- std::vector<std::string> uris;
- uris.push_back(mUri.asString());
- rewriteResult(uris);
-}
-
-void LLAres::UriRewriteResponder::querySuccess()
-{
- std::vector<std::string> uris;
-
- if (mType != RES_SRV)
- {
- goto bail;
- }
-
- for (size_t i = 0; i < mAnswers.size(); i++)
- {
- const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
-
- if (r->type() == RES_SRV)
- {
- // Check the domain in the response to ensure that it's
- // the same as the domain in the request, so that bad guys
- // can't forge responses that point to their own login
- // servers with their own certificates.
-
- // Hard-coding the domain to check here is a bit of a
- // hack. Hoist it to an outer caller if anyone ever needs
- // this functionality on other domains.
-
- static const std::string domain(".lindenlab.com");
- const std::string &host = r->host();
-
- std::string::size_type s = host.find(domain) + domain.length();
-
- if (s != host.length() && s != host.length() - 1)
- {
- continue;
- }
-
- LLURI uri(mUri.scheme(),
- mUri.userName(),
- mUri.password(),
- r->host(),
- mUri.defaultPort() ? r->port() : mUri.hostPort(),
- mUri.escapedPath(),
- mUri.escapedQuery());
- uris.push_back(uri.asString());
- }
- }
-
- if (!uris.empty())
- {
- goto done;
- }
-
-bail:
- uris.push_back(mUri.asString());
-
-done:
- rewriteResult(uris);
-}
-
-void LLAres::UriRewriteResponder::rewriteResult(
- const std::vector<std::string> &uris)
-{
- LL_INFOS() << "LLAres::UriRewriteResponder::rewriteResult not implemented"
- << LL_ENDL;
-
- for (size_t i = 0; i < uris.size(); i++)
- {
- LL_INFOS() << "[" << i << "] " << uris[i] << LL_ENDL;
- }
-}
diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h
deleted file mode 100755
index c727363b60..0000000000
--- a/indra/llmessage/llares.h
+++ /dev/null
@@ -1,583 +0,0 @@
-/**
- * @file llares.h
- * @author Bryan O'Sullivan
- * @date 2007-08-15
- * @brief Wrapper for asynchronous DNS lookups.
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLARES_H
-#define LL_LLARES_H
-
-#ifdef LL_WINDOWS
-// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
-// we need to include them first to work around it, but the headers issue warnings
-# pragma warning(push)
-# pragma warning(disable:4996)
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# pragma warning(pop)
-#endif
-
-#ifdef LL_USESYSTEMLIBS
-# include <ares.h>
-#else
-# include <ares/ares.h>
-#endif
-
-#include "llpointer.h"
-#include "llrefcount.h"
-#include "lluri.h"
-
-#include <boost/shared_ptr.hpp>
-
-class LLQueryResponder;
-class LLAresListener;
-
-/**
- * @brief Supported DNS RR types.
- */
-enum LLResType
-{
- RES_INVALID = 0, /**< Cookie. */
- RES_A = 1, /**< "A" record. IPv4 address. */
- RES_NS = 2, /**< "NS" record. Authoritative server. */
- RES_CNAME = 5, /**< "CNAME" record. Canonical name. */
- RES_PTR = 12, /**< "PTR" record. Domain name pointer. */
- RES_AAAA = 28, /**< "AAAA" record. IPv6 Address. */
- RES_SRV = 33, /**< "SRV" record. Server Selection. */
- RES_MAX = 65536 /**< Sentinel; RR types are 16 bits wide. */
-};
-
-/**
- * @class LLDnsRecord
- * @brief Base class for all DNS RR types.
- */
-class LLDnsRecord : public LLRefCount
-{
-protected:
- friend class LLQueryResponder;
-
- LLResType mType;
- std::string mName;
- unsigned mTTL;
-
- virtual int parse(const char *buf, size_t len, const char *pos,
- size_t rrlen) = 0;
-
- LLDnsRecord(LLResType type, const std::string &name, unsigned ttl);
-
-public:
- /**
- * @brief Record name.
- */
- const std::string &name() const { return mName; }
-
- /**
- * @brief Time-to-live value, in seconds.
- */
- unsigned ttl() const { return mTTL; }
-
- /**
- * @brief RR type.
- */
- LLResType type() const { return mType; }
-};
-
-/**
- * @class LLAddrRecord
- * @brief Base class for address-related RRs.
- */
-class LLAddrRecord : public LLDnsRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLAddrRecord(LLResType type, const std::string &name, unsigned ttl);
-
- union
- {
- sockaddr sa;
- sockaddr_in sin;
- sockaddr_in6 sin6;
- } mSA;
-
- socklen_t mSize;
-
-public:
- /**
- * @brief Generic socket address.
- */
- const sockaddr &addr() const { return mSA.sa; }
-
- /**
- * @brief Size of the socket structure.
- */
- socklen_t size() const { return mSize; }
-};
-
-/**
- * @class LLARecord
- * @brief A RR, for IPv4 addresses.
- */
-class LLARecord : public LLAddrRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLARecord(const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- /**
- * @brief Socket address.
- */
- const sockaddr_in &addr_in() const { return mSA.sin; }
-};
-
-/**
- * @class LLAaaaRecord
- * @brief AAAA RR, for IPv6 addresses.
- */
-class LLAaaaRecord : public LLAddrRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLAaaaRecord(const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- /**
- * @brief Socket address.
- */
- const sockaddr_in6 &addr_in6() const { return mSA.sin6; }
-};
-
-/**
- * @class LLHostRecord
- * @brief Base class for host-related RRs.
- */
-class LLHostRecord : public LLDnsRecord
-{
-protected:
- LLHostRecord(LLResType type, const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
- std::string mHost;
-
-public:
- /**
- * @brief Host name.
- */
- const std::string &host() const { return mHost; }
-};
-
-/**
- * @class LLCnameRecord
- * @brief CNAME RR.
- */
-class LLCnameRecord : public LLHostRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLCnameRecord(const std::string &name, unsigned ttl);
-};
-
-/**
- * @class LLPtrRecord
- * @brief PTR RR.
- */
-class LLPtrRecord : public LLHostRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLPtrRecord(const std::string &name, unsigned ttl);
-};
-
-/**
- * @class LLSrvRecord
- * @brief SRV RR.
- */
-class LLSrvRecord : public LLHostRecord
-{
-protected:
- U16 mPriority;
- U16 mWeight;
- U16 mPort;
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- LLSrvRecord(const std::string &name, unsigned ttl);
-
- /**
- * @brief Service priority.
- */
- U16 priority() const { return mPriority; }
-
- /**
- * @brief Service weight.
- */
- U16 weight() const { return mWeight; }
-
- /**
- * @brief Port number of service.
- */
- U16 port() const { return mPort; }
-
- /**
- * @brief Functor for sorting SRV records by priority.
- */
- struct ComparePriorityLowest
- {
- bool operator()(const LLSrvRecord& lhs, const LLSrvRecord& rhs)
- {
- return lhs.mPriority < rhs.mPriority;
- }
- };
-};
-
-/**
- * @class LLNsRecord
- * @brief NS RR.
- */
-class LLNsRecord : public LLHostRecord
-{
-public:
- LLNsRecord(const std::string &name, unsigned ttl);
-};
-
-class LLQueryResponder;
-
-/**
- * @class LLAres
- * @brief Asynchronous address resolver.
- */
-class LLAres
-{
-public:
- /**
- * @class HostResponder
- * @brief Base class for responding to hostname lookups.
- * @see LLAres::getHostByName
- */
- class HostResponder : public LLRefCount
- {
- public:
- virtual ~HostResponder();
-
- virtual void hostResult(const hostent *ent);
- virtual void hostError(int code);
- };
-
- /**
- * @class NameInfoResponder
- * @brief Base class for responding to address lookups.
- * @see LLAres::getNameInfo
- */
- class NameInfoResponder : public LLRefCount
- {
- public:
- virtual ~NameInfoResponder();
-
- virtual void nameInfoResult(const char *node, const char *service);
- virtual void nameInfoError(int code);
- };
-
- /**
- * @class QueryResponder
- * @brief Base class for responding to custom searches.
- * @see LLAres::search
- */
- class QueryResponder : public LLRefCount
- {
- public:
- virtual ~QueryResponder();
-
- virtual void queryResult(const char *buf, size_t len);
- virtual void queryError(int code);
- };
-
- class SrvResponder;
- class UriRewriteResponder;
-
- LLAres();
-
- ~LLAres();
-
- /**
- * Cancel all outstanding requests. The error methods of the
- * corresponding responders will be called, with ARES_ETIMEOUT.
- */
- void cancel();
-
- /**
- * Look up the address of a host.
- *
- * @param name name of host to look up
- * @param resp responder to call with result
- * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
- */
- void getHostByName(const std::string &name, HostResponder *resp,
- int family = AF_INET) {
- getHostByName(name.c_str(), resp, family);
- }
-
- /**
- * Look up the address of a host.
- *
- * @param name name of host to look up
- * @param resp responder to call with result
- * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
- */
- void getHostByName(const char *name, HostResponder *resp,
- int family = PF_INET);
-
- /**
- * Look up the name associated with a socket address.
- *
- * @param sa socket address to look up
- * @param salen size of socket address
- * @param flags flags to use
- * @param resp responder to call with result
- */
- void getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
- NameInfoResponder *resp);
-
- /**
- * Look up SRV (service location) records for a service name.
- *
- * @param name service name (e.g. "_https._tcp.login.agni.lindenlab.com")
- * @param resp responder to call with result
- */
- void getSrvRecords(const std::string &name, SrvResponder *resp);
-
- /**
- * Rewrite a URI, using SRV (service location) records for its
- * protocol if available. If no SRV records are published, the
- * existing URI is handed to the responder.
- *
- * @param uri URI to rewrite
- * @param resp responder to call with result
- */
- void rewriteURI(const std::string &uri,
- UriRewriteResponder *resp);
-
- /**
- * Start a custom search.
- *
- * @param query query to make
- * @param type type of query to perform
- * @param resp responder to call with result
- */
- void search(const std::string &query, LLResType type,
- QueryResponder *resp);
-
- /**
- * Process any outstanding queries. This method takes an optional
- * timeout parameter (specified in microseconds). If provided, it
- * will block the calling thread for that length of time to await
- * possible responses. A timeout of zero will return immediately
- * if there are no responses or timeouts to process.
- *
- * @param timeoutUsecs number of microseconds to block before timing out
- * @return whether any responses were processed
- */
- bool process(U64 timeoutUsecs = 0);
-
- /**
- * Process all outstanding queries, blocking the calling thread
- * until all have either been responded to or timed out.
- *
- * @return whether any responses were processed
- */
- bool processAll();
-
- /**
- * Expand a DNS-encoded compressed string into a normal string.
- *
- * @param encoded the encoded name (null-terminated)
- * @param abuf the response buffer in which the string is embedded
- * @param alen the length of the response buffer
- * @param s the string into which to place the result
- * @return ARES_SUCCESS on success, otherwise an error indicator
- */
- static int expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s) {
- size_t ignore;
- return expandName(encoded, abuf, alen, s, ignore);
- }
-
- static int expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s, size_t &enclen);
-
- /**
- * Return a string describing an error code.
- */
- static const char *strerror(int code);
-
- bool isInitialized(void) { return mInitSuccess; }
-
-protected:
- ares_channel chan_;
- bool mInitSuccess;
- // boost::scoped_ptr would actually fit the requirement better, but it
- // can't handle incomplete types as boost::shared_ptr can.
- boost::shared_ptr<LLAresListener> mListener;
-};
-
-/**
- * An ordered collection of DNS resource records.
- */
-typedef std::vector<LLPointer<LLDnsRecord> > dns_rrs_t;
-
-/**
- * @class LLQueryResponder
- * @brief Base class for friendly handling of DNS query responses.
- *
- * This class parses a DNS response and represents it in a friendly
- * manner.
- *
- * @see LLDnsRecord
- * @see LLARecord
- * @see LLNsRecord
- * @see LLCnameRecord
- * @see LLPtrRecord
- * @see LLAaaaRecord
- * @see LLSrvRecord
- */
-class LLQueryResponder : public LLAres::QueryResponder
-{
-protected:
- int mResult;
- std::string mQuery;
- LLResType mType;
-
- dns_rrs_t mAnswers;
- dns_rrs_t mAuthorities;
- dns_rrs_t mAdditional;
-
- /**
- * Parse a single RR.
- */
- int parseRR(const char *buf, size_t len, const char *&pos,
- LLPointer<LLDnsRecord> &r);
- /**
- * Parse one section of a response.
- */
- int parseSection(const char *buf, size_t len,
- size_t count, const char *& pos, dns_rrs_t &rrs);
-
- void queryResult(const char *buf, size_t len);
- virtual void querySuccess();
-
-public:
- LLQueryResponder();
-
- /**
- * Indicate whether the response could be parsed successfully.
- */
- bool valid() const { return mResult == ARES_SUCCESS; }
-
- /**
- * The more detailed result of parsing the response.
- */
- int result() const { return mResult; }
-
- /**
- * Return the query embedded in the response.
- */
- const std::string &query() const { return mQuery; }
-
- /**
- * Return the contents of the "answers" section of the response.
- */
- const dns_rrs_t &answers() const { return mAnswers; }
-
- /**
- * Return the contents of the "authorities" section of the
- * response.
- */
- const dns_rrs_t &authorities() const { return mAuthorities; }
-
- /**
- * Return the contents of the "additional records" section of the
- * response.
- */
- const dns_rrs_t &additional() const { return mAdditional; }
-};
-
-/**
- * @class LLAres::SrvResponder
- * @brief Class for handling SRV query responses.
- */
-class LLAres::SrvResponder : public LLQueryResponder
-{
-public:
- friend void LLAres::getSrvRecords(const std::string &name,
- SrvResponder *resp);
- void querySuccess();
- void queryError(int code);
-
- virtual void srvResult(const dns_rrs_t &ents);
- virtual void srvError(int code);
-};
-
-/**
- * @class LLAres::UriRewriteResponder
- * @brief Class for handling URI rewrites based on SRV records.
- */
-class LLAres::UriRewriteResponder : public LLQueryResponder
-{
-protected:
- LLURI mUri;
-
-public:
- friend void LLAres::rewriteURI(const std::string &uri,
- UriRewriteResponder *resp);
- void querySuccess();
- void queryError(int code);
-
- virtual void rewriteResult(const std::vector<std::string> &uris);
-};
-
-/**
- * Singleton responder.
- */
-extern LLAres *gAres;
-
-/**
- * Set up the singleton responder. It's safe to call this more than
- * once from within a single thread, but this function is not
- * thread safe.
- */
-extern LLAres *ll_init_ares();
-extern void ll_cleanup_ares();
-
-#endif // LL_LLARES_H
diff --git a/indra/llmessage/llareslistener.cpp b/indra/llmessage/llareslistener.cpp
deleted file mode 100755
index 3d65906b98..0000000000
--- a/indra/llmessage/llareslistener.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * @file llareslistener.cpp
- * @author Nat Goodspeed
- * @date 2009-03-18
- * @brief Implementation for llareslistener.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "llareslistener.h"
-// STL headers
-// std headers
-// external library headers
-// other Linden headers
-#include "llares.h"
-#include "llerror.h"
-#include "llevents.h"
-#include "llsdutil.h"
-
-LLAresListener::LLAresListener(LLAres* llares):
- LLEventAPI("LLAres",
- "LLAres listener to request DNS operations"),
- mAres(llares)
-{
- // add() every method we want to be able to invoke via this event API.
- // Optional last parameter validates expected LLSD request structure.
- add("rewriteURI",
- "Given [\"uri\"], return on [\"reply\"] an array of alternative URIs.\n"
- "On failure, returns an array containing only the original URI, so\n"
- "failure case can be processed like success case.",
- &LLAresListener::rewriteURI,
- LLSD().with("uri", LLSD()).with("reply", LLSD()));
-}
-
-/// This UriRewriteResponder subclass packages returned URIs as an LLSD
-/// array to send back to the requester.
-class UriRewriteResponder: public LLAres::UriRewriteResponder
-{
-public:
- /**
- * Specify the request, containing the event pump name on which to send
- * the reply.
- */
- UriRewriteResponder(const LLSD& request):
- mReqID(request),
- mPumpName(request["reply"])
- {}
-
- /// Called by base class with results. This is called in both the
- /// success and error cases. On error, the calling logic passes the
- /// original URI.
- virtual void rewriteResult(const std::vector<std::string>& uris)
- {
- LLSD result;
- for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
- ui != uend; ++ui)
- {
- result.append(*ui);
- }
- // This call knows enough to avoid trying to insert a map key into an
- // LLSD array. It's there so that if, for any reason, we ever decide
- // to change the response from array to map, it will Just Start Working.
- mReqID.stamp(result);
- LLEventPumps::instance().obtain(mPumpName).post(result);
- }
-
-private:
- LLReqID mReqID;
- const std::string mPumpName;
-};
-
-void LLAresListener::rewriteURI(const LLSD& data)
-{
- if (mAres)
- {
- mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
- }
- else
- {
- LL_INFOS() << "LLAresListener::rewriteURI requested without Ares present. Ignoring: " << data << LL_ENDL;
- }
-}
diff --git a/indra/llmessage/llareslistener.h b/indra/llmessage/llareslistener.h
deleted file mode 100755
index 780dcdd9c5..0000000000
--- a/indra/llmessage/llareslistener.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @file llareslistener.h
- * @author Nat Goodspeed
- * @date 2009-03-18
- * @brief LLEventPump API for LLAres. This header doesn't actually define the
- * API; the API is defined by the pump name on which this class
- * listens, and by the expected content of LLSD it receives.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_LLARESLISTENER_H)
-#define LL_LLARESLISTENER_H
-
-#include "lleventapi.h"
-
-class LLAres;
-class LLSD;
-
-/// Listen on an LLEventPump with specified name for LLAres request events.
-class LLAresListener: public LLEventAPI
-{
-public:
- /// Bind the LLAres instance to use (e.g. gAres)
- LLAresListener(LLAres* llares);
-
-private:
- /// command["op"] == "rewriteURI"
- void rewriteURI(const LLSD& data);
-
- LLAres* mAres;
-};
-
-#endif /* ! defined(LL_LLARESLISTENER_H) */
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 5740b8f7da..0d8aaf2269 100755
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -1609,3 +1609,4 @@ void LLAssetStorage::markAssetToxic( const LLUUID& uuid )
}
}
+
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 1bb4acea9e..c3d31ba84c 100755
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -27,7 +27,6 @@
#ifndef LL_LLASSETSTORAGE_H
#define LL_LLASSETSTORAGE_H
-
#include <string>
#include "lluuid.h"
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index d262862c80..61f18ed63e 100755
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -195,7 +195,7 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
bool success = true;
LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", LLAvatarNameCache::sHttpPolicy);
- LLSD results = httpAdapter.getAndYield(sHttpRequest, url);
+ LLSD results = httpAdapter.getAndSuspend(sHttpRequest, url);
LLSD httpResults;
LL_DEBUGS() << results << LL_ENDL;
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index 062f2e6e42..f0fe1ab01b 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -27,13 +27,16 @@
#include "linden_common.h"
#include "llcoproceduremanager.h"
+#include <boost/assign.hpp>
//=========================================================================
// Map of pool sizes for known pools
-static std::map<std::string, U32> DefaultPoolSizes;
-
// *TODO$: When C++11 this can be initialized here as follows:
// = {{"AIS", 25}, {"Upload", 1}}
+static std::map<std::string, U32> DefaultPoolSizes =
+ boost::assign::map_list_of
+ (std::string("Upload"), 1)
+ (std::string("AIS"), 25);
#define DEFAULT_POOL_SIZE 5
@@ -55,7 +58,7 @@ public:
LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc);
/// Cancel a coprocedure. If the coprocedure is already being actively executed
- /// this method calls cancelYieldingOperation() on the associated HttpAdapter
+ /// this method calls cancelSuspendedOperation() on the associated HttpAdapter
/// If it has not yet been dequeued it is simply removed from the queue.
bool cancelCoprocedure(const LLUUID &id);
@@ -124,8 +127,6 @@ private:
//=========================================================================
LLCoprocedureManager::LLCoprocedureManager()
{
- DefaultPoolSizes.insert(std::map<std::string, U32>::value_type("Upload", 1));
- DefaultPoolSizes.insert(std::map<std::string, U32>::value_type("AIS", 25));
}
LLCoprocedureManager::~LLCoprocedureManager()
@@ -139,6 +140,9 @@ LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::
std::string keyName = "PoolSize" + poolName;
int size = 0;
+ if (poolName.empty())
+ LL_ERRS("CoprocedureManager") << "Poolname must not be empty" << LL_ENDL;
+
if (mPropertyQueryFn && !mPropertyQueryFn.empty())
{
size = mPropertyQueryFn(keyName);
@@ -158,9 +162,11 @@ LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::
LL_WARNS() << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
}
- poolPtr_t pool = poolPtr_t(new LLCoprocedurePool(poolName, size));
+ poolPtr_t pool(new LLCoprocedurePool(poolName, size));
mPoolMap.insert(poolMap_t::value_type(poolName, pool));
+ if (!pool)
+ LL_ERRS("CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL;
return pool;
}
@@ -181,12 +187,6 @@ LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const s
targetPool = (*it).second;
}
- if (!targetPool)
- {
- LL_WARNS() << "LLCoprocedureManager unable to create coprocedure pool named \"" << pool << "\"" << LL_ENDL;
- return LLUUID::null;
- }
-
return targetPool->enqueueCoprocedure(name, proc);
}
@@ -285,14 +285,12 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
{
for (size_t count = 0; count < mPoolSize; ++count)
{
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter =
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t(
- new LLCoreHttpUtil::HttpCoroutineAdapter( mPoolName + "Adapter", mHTTPPolicy));
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter( mPoolName + "Adapter", mHTTPPolicy));
- std::string uploadCoro = LLCoros::instance().launch("LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro",
+ std::string pooledCoro = LLCoros::instance().launch("LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro",
boost::bind(&LLCoprocedurePool::coprocedureInvokerCoro, this, httpAdapter));
- mCoroMapping.insert(CoroAdapterMap_t::value_type(uploadCoro, httpAdapter));
+ mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter));
}
LL_INFOS() << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items." << LL_ENDL;
@@ -312,16 +310,13 @@ void LLCoprocedurePool::shutdown(bool hardShutdown)
for (it = mCoroMapping.begin(); it != mCoroMapping.end(); ++it)
{
- if (!(*it).first.empty())
+ if (hardShutdown)
{
- if (hardShutdown)
- {
- LLCoros::instance().kill((*it).first);
- }
+ LLCoros::instance().kill((*it).first);
}
if ((*it).second)
{
- (*it).second->cancelYieldingOperation();
+ (*it).second->cancelSuspendedOperation();
}
}
@@ -350,7 +345,7 @@ bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id)
if (itActive != mActiveCoprocs.end())
{
LL_INFOS() << "Found and canceling active coprocedure with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
- (*itActive).second->cancelYieldingOperation();
+ (*itActive).second->cancelSuspendedOperation();
mActiveCoprocs.erase(itActive);
return true;
}
@@ -365,7 +360,7 @@ bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id)
}
}
- LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found." << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+ LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found in pool \"" << mPoolName << "\"" << LL_ENDL;
return false;
}
@@ -376,7 +371,7 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
while (!mShutdown)
{
- llcoro::waitForEventOn(mWakeupTrigger);
+ llcoro::suspendUntilEventOn(mWakeupTrigger);
if (mShutdown)
break;
@@ -384,7 +379,7 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
{
QueuedCoproc::ptr_t coproc = mPendingCoprocs.front();
mPendingCoprocs.pop_front();
- mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter));
+ ActiveCoproc_t::iterator itActive = mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter)).first;
LL_INFOS() << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
@@ -404,11 +399,7 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;
- ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(coproc->mId);
- if (itActive != mActiveCoprocs.end())
- {
- mActiveCoprocs.erase(itActive);
- }
+ mActiveCoprocs.erase(itActive);
}
}
}
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index d342888255..9a23ede81b 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -35,7 +35,8 @@
#include "llsd.h"
#include "llsdjson.h"
#include "llsdserialize.h"
-#include "reader.h"
+#include "reader.h" // JSON
+#include "writer.h" // JSON
#include "llvfile.h"
#include "message.h" // for getting the port
@@ -45,6 +46,10 @@ using namespace LLCore;
namespace LLCoreHttpUtil
{
+
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+
void logMessageSuccess(std::string logAuth, std::string url, std::string message)
{
LL_INFOS() << logAuth << " Success '" << message << "' for " << url << LL_ENDL;
@@ -104,7 +109,7 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,
const LLSD & body,
const HttpOptions::ptr_t &options,
const HttpHeaders::ptr_t &headers,
- HttpHandler * handler)
+ const HttpHandler::ptr_t &handler)
{
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
@@ -131,7 +136,7 @@ HttpHandle requestPutWithLLSD(HttpRequest * request,
const LLSD & body,
const HttpOptions::ptr_t &options,
const HttpHeaders::ptr_t &headers,
- HttpHandler * handler)
+ const HttpHandler::ptr_t &handler)
{
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
@@ -157,7 +162,7 @@ HttpHandle requestPatchWithLLSD(HttpRequest * request,
const LLSD & body,
const HttpOptions::ptr_t &options,
const HttpHeaders::ptr_t &headers,
- HttpHandler * handler)
+ const HttpHandler::ptr_t &handler)
{
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
@@ -243,13 +248,32 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
if (!status)
{
+ bool parseSuccess(false);
result = LLSD::emptyMap();
+ LLCore::HttpStatus::type_enum_t errType = status.getType();
+
LL_WARNS()
<< "\n--------------------------------------------------------------------------\n"
- << " Error[" << status.getType() << "] cannot access url '" << response->getRequestURL()
+ << " Error[" << status.toTerseString() << "] cannot access url '" << response->getRequestURL()
<< "' because " << status.toString()
<< "\n--------------------------------------------------------------------------"
<< LL_ENDL;
+ if ((errType >= 400) && (errType < 500))
+ {
+ LLSD body = this->parseBody(response, parseSuccess);
+ if (!body.isUndefined())
+ {
+ if (!body.isMap())
+ {
+ result[HttpCoroutineAdapter::HTTP_RESULTS_CONTENT] = body;
+ }
+ else
+ {
+ result = body;
+ }
+ }
+
+ }
}
else
{
@@ -258,8 +282,6 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
buildStatusEntry(response, status, result);
-#if 1
- // commenting out, but keeping since this can be useful for debugging
if (!status)
{
LLSD &httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS];
@@ -271,10 +293,11 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
bas >> std::noskipws;
bodyData.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>());
httpStatus["error_body"] = LLSD(bodyData);
-
+#if 1
+ // commenting out, but keeping since this can be useful for debugging
LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL;
- }
#endif
+ }
mReplyPump.post(result);
}
@@ -340,6 +363,7 @@ public:
protected:
virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+ virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success);
};
//-------------------------------------------------------------------------
@@ -353,8 +377,12 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
{
LLSD result;
- const bool emit_parse_errors = false;
+// const bool emit_parse_errors = false;
+ bool success(false);
+ result = parseBody(response, success);
+
+#if 0
bool parsed = !((response->getBodySize() == 0) ||
!LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result));
@@ -374,9 +402,26 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
status = LLCore::HttpStatus(499, "Failed to deserialize LLSD.");
}
}
+#endif
- if (result.isUndefined())
- { // If we've gotten to this point and the result LLSD is still undefined
+ if (!success)
+ {
+#if 1
+ // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+ LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
+ const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
+
+ if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
+ {
+ std::string thebody = LLCoreHttpUtil::responseToString(response);
+ LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
+ << " body: " << thebody << LL_ENDL;
+
+ // Replace the status with a new one indicating the failure.
+ status = LLCore::HttpStatus(499, "Failed to deserialize LLSD.");
+ }
+#endif
+ // If we've gotten to this point and the result LLSD is still undefined
// either there was an issue deserializing the body or the response was
// blank. Create an empty map to hold the result either way.
result = LLSD::emptyMap();
@@ -393,6 +438,24 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
return result;
}
+LLSD HttpCoroLLSDHandler::parseBody(LLCore::HttpResponse *response, bool &success)
+{
+ success = true;
+ if (response->getBodySize() == 0)
+ return LLSD();
+
+ LLSD result;
+
+ if (!LLCoreHttpUtil::responseToLLSD(response, true, result))
+ {
+ success = false;
+ return LLSD();
+ }
+
+ return result;
+}
+
+
//========================================================================
/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for
/// interacting with coroutines.
@@ -407,6 +470,7 @@ public:
HttpCoroRawHandler(LLEventStream &reply);
virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+ virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success);
};
//-------------------------------------------------------------------------
@@ -461,6 +525,12 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::
return result;
}
+LLSD HttpCoroRawHandler::parseBody(LLCore::HttpResponse *response, bool &success)
+{
+ success = true;
+ return LLSD();
+}
+
//========================================================================
/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for
/// interacting with coroutines.
@@ -475,6 +545,7 @@ public:
HttpCoroJSONHandler(LLEventStream &reply);
virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+ virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success);
};
//-------------------------------------------------------------------------
@@ -512,6 +583,31 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
return result;
}
+LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &success)
+{
+ success = true;
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return LLSD();
+ }
+
+ LLCore::BufferArrayStream bas(body);
+ Json::Value jsonRoot;
+
+ try
+ {
+ bas >> jsonRoot;
+ }
+ catch (std::runtime_error e)
+ {
+ success = false;
+ return LLSD();
+ }
+
+ // Convert the JSON structure to LLSD
+ return LlsdFromJson(jsonRoot);
+}
//========================================================================
HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) :
@@ -562,20 +658,20 @@ HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
HttpCoroutineAdapter::~HttpCoroutineAdapter()
{
- cancelYieldingOperation();
+ cancelSuspendedOperation();
}
-LLSD HttpCoroutineAdapter::postAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName, true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return postAndYield_(request, url, body, options, headers, httpHandler);
+ return postAndSuspend_(request, url, body, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -588,7 +684,7 @@ LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
mPolicyId, mPriority, url, body, options, headers,
- handler.get());
+ handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -596,35 +692,35 @@ LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::postAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName, true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return postAndYield_(request, url, rawbody, options, headers, httpHandler);
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::postRawAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::postRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName, true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroRawHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroRawHandler(replyPump));
- return postAndYield_(request, url, rawbody, options, headers, httpHandler);
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
}
// *TODO: This functionality could be moved into the LLCore::Http library itself
// by having the CURL layer read the file directly.
-LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, std::string fileName,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
@@ -648,12 +744,12 @@ LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request,
}
}
- return postAndYield(request, url, fileData, options, headers);
+ return postAndSuspend(request, url, fileData, options, headers);
}
// *TODO: This functionality could be moved into the LLCore::Http library itself
// by having the CURL layer read the file directly.
-LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
@@ -673,11 +769,33 @@ LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request,
delete[] fileBuffer;
}
- return postAndYield(request, url, fileData, options, headers);
+ return postAndSuspend(request, url, fileData, options, headers);
}
+LLSD HttpCoroutineAdapter::postJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+
+ {
+ LLCore::BufferArrayStream outs(rawbody.get());
+ Json::Value root = LlsdToJson(body);
+ Json::FastWriter writer;
+
+ LL_WARNS("Http::post") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL;
+
+ outs << writer.write(root);
+ }
+
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
-LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
+
+LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -689,7 +807,7 @@ LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, mPriority, url, rawbody.get(),
- options, headers, handler.get());
+ options, headers, handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -697,23 +815,44 @@ LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::putAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::putAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return putAndYield_(request, url, body, options, headers, httpHandler);
+ return putAndSuspend_(request, url, body, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::putAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::putJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+
+ {
+ LLCore::BufferArrayStream outs(rawbody.get());
+ Json::Value root = LlsdToJson(body);
+ Json::FastWriter writer;
+
+ LL_WARNS("Http::put") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL;
+ outs << writer.write(root);
+ }
+
+ return putAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -726,7 +865,7 @@ LLSD HttpCoroutineAdapter::putAndYield_(LLCore::HttpRequest::ptr_t &request,
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
mPolicyId, mPriority, url, body, options, headers,
- handler.get());
+ handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -734,43 +873,70 @@ LLSD HttpCoroutineAdapter::putAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::getAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLCore::BufferArray::ptr_t & rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestPut(mPolicyId, mPriority,
+ url, rawbody.get(), options, headers, handler);
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+
+LLSD HttpCoroutineAdapter::getAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return getAndYield_(request, url, options, headers, httpHandler);
+ return getAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::getRawAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::getRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroRawHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroRawHandler(replyPump));
- return getAndYield_(request, url, options, headers, httpHandler);
+ return getAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::getJsonAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::getJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroJSONHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
- return getAndYield_(request, url, options, headers, httpHandler);
+ return getAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::getAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -781,7 +947,7 @@ LLSD HttpCoroutineAdapter::getAndYield_(LLCore::HttpRequest::ptr_t &request,
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, mPriority,
- url, options, headers, handler.get());
+ url, options, headers, handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -789,24 +955,35 @@ LLSD HttpCoroutineAdapter::getAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::deleteAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return deleteAndYield_(request, url, options, headers, httpHandler);
+ return deleteAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::deleteAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ return deleteAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpOptions::ptr_t &options,
LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler)
{
@@ -816,7 +993,7 @@ LLSD HttpCoroutineAdapter::deleteAndYield_(LLCore::HttpRequest::ptr_t &request,
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, mPriority,
- url, options, headers, handler.get());
+ url, options, headers, handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -824,24 +1001,24 @@ LLSD HttpCoroutineAdapter::deleteAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::patchAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::patchAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
- return patchAndYield_(request, url, body, options, headers, httpHandler);
+ return patchAndSuspend_(request, url, body, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::patchAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -854,7 +1031,7 @@ LLSD HttpCoroutineAdapter::patchAndYield_(LLCore::HttpRequest::ptr_t &request,
// pointer from the smart pointer is safe in this case.
LLCore::HttpHandle hhandle = requestPatchWithLLSD(request,
mPolicyId, mPriority, url, body, options, headers,
- handler.get());
+ handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -862,28 +1039,28 @@ LLSD HttpCoroutineAdapter::patchAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::copyAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::copyAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
if (!headers)
headers.reset(new LLCore::HttpHeaders);
headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
- return copyAndYield_(request, url, options, headers, httpHandler);
+ return copyAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::copyAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -896,7 +1073,7 @@ LLSD HttpCoroutineAdapter::copyAndYield_(LLCore::HttpRequest::ptr_t &request,
// pointer from the smart pointer is safe in this case.
//
LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, mPriority, url,
- options, headers, handler.get());
+ options, headers, handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -904,28 +1081,28 @@ LLSD HttpCoroutineAdapter::copyAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
}
-LLSD HttpCoroutineAdapter::moveAndYield(LLCore::HttpRequest::ptr_t request,
+LLSD HttpCoroutineAdapter::moveAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
{
LLEventStream replyPump(mAdapterName + "Reply", true);
- HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
if (!headers)
headers.reset(new LLCore::HttpHeaders);
headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
- return moveAndYield_(request, url, options, headers, httpHandler);
+ return moveAndSuspend_(request, url, options, headers, httpHandler);
}
-LLSD HttpCoroutineAdapter::moveAndYield_(LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler)
@@ -938,7 +1115,7 @@ LLSD HttpCoroutineAdapter::moveAndYield_(LLCore::HttpRequest::ptr_t &request,
// pointer from the smart pointer is safe in this case.
//
LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, mPriority, url,
- options, headers, handler.get());
+ options, headers, handler);
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
@@ -946,7 +1123,7 @@ LLSD HttpCoroutineAdapter::moveAndYield_(LLCore::HttpRequest::ptr_t &request,
}
saveState(hhandle, request, handler);
- LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
cleanState();
return results;
@@ -973,7 +1150,7 @@ void HttpCoroutineAdapter::checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &heade
}
-void HttpCoroutineAdapter::cancelYieldingOperation()
+void HttpCoroutineAdapter::cancelSuspendedOperation()
{
LLCore::HttpRequest::ptr_t request = mWeakRequest.lock();
HttpCoroHandler::ptr_t handler = mWeakHandler.lock();
@@ -981,7 +1158,7 @@ void HttpCoroutineAdapter::cancelYieldingOperation()
{
cleanState();
LL_INFOS() << "Canceling yielding request!" << LL_ENDL;
- request->requestCancel(mYieldingHandle, handler.get());
+ request->requestCancel(mYieldingHandle, handler);
}
}
@@ -1058,7 +1235,7 @@ void HttpCoroutineAdapter::trivialGetCoro(std::string url, LLCore::HttpRequest::
LL_INFOS("HttpCoroutineAdapter", "genericGetCoro") << "Generic GET for " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -1109,7 +1286,7 @@ void HttpCoroutineAdapter::trivialPostCoro(std::string url, LLCore::HttpRequest:
LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h
index 31a73bb900..d21f5ff45c 100644
--- a/indra/llmessage/llcorehttputil.h
+++ b/indra/llmessage/llcorehttputil.h
@@ -57,6 +57,7 @@
///
namespace LLCoreHttpUtil
{
+ extern const F32 HTTP_REQUEST_EXPIRY_SECS;
/// Attempt to convert a response object's contents to LLSD.
/// It is expected that the response body will be of non-zero
@@ -113,7 +114,7 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
- LLCore::HttpHandler * handler);
+ const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
@@ -122,7 +123,7 @@ inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & reque
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
- LLCore::HttpHandler * handler)
+ const LLCore::HttpHandler::ptr_t & handler)
{
return requestPostWithLLSD(request.get(), policy_id, priority,
url, body, options, headers, handler);
@@ -133,7 +134,7 @@ inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & reque
LLCore::HttpRequest::priority_t priority,
const std::string & url,
const LLSD & body,
- LLCore::HttpHandler * handler)
+ const LLCore::HttpHandler::ptr_t &handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
@@ -166,7 +167,7 @@ LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
- LLCore::HttpHandler * handler);
+ const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
@@ -175,7 +176,7 @@ inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & reques
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
- LLCore::HttpHandler * handler)
+ LLCore::HttpHandler::ptr_t handler)
{
return requestPutWithLLSD(request.get(), policy_id, priority,
url, body, options, headers, handler);
@@ -186,7 +187,7 @@ inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & reques
LLCore::HttpRequest::priority_t priority,
const std::string & url,
const LLSD & body,
- LLCore::HttpHandler * handler)
+ LLCore::HttpHandler::ptr_t handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
@@ -218,7 +219,7 @@ LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
- LLCore::HttpHandler * handler);
+ const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
@@ -227,7 +228,7 @@ inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & requ
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
- LLCore::HttpHandler * handler)
+ const LLCore::HttpHandler::ptr_t & handler)
{
return requestPatchWithLLSD(request.get(), policy_id, priority,
url, body, options, headers, handler);
@@ -238,7 +239,7 @@ inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & requ
LLCore::HttpRequest::priority_t priority,
const std::string & url,
const LLSD & body,
- LLCore::HttpHandler * handler)
+ const LLCore::HttpHandler::ptr_t &handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
@@ -281,6 +282,7 @@ public:
protected:
/// this method may modify the status value
virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0;
+ virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) = 0;
private:
void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result);
@@ -329,118 +331,157 @@ public:
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD postAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD postAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD postAndYield(LLCore::HttpRequest::ptr_t &request,
+
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
- return postAndYield(request, url, body,
+ return postAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
- LLSD postAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpHeaders::ptr_t &headers)
{
- return postAndYield(request, url, rawbody,
+ return postAndSuspend(request, url, rawbody,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
- LLSD postRawAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD postRawAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpHeaders::ptr_t &headers)
{
- return postRawAndYield(request, url, rawbody,
+ return postRawAndSuspend(request, url, rawbody,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
- LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, std::string fileName,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD postFileAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, std::string fileName,
LLCore::HttpHeaders::ptr_t &headers)
{
- return postFileAndYield(request, url, fileName,
+ return postFileAndSuspend(request, url, fileName,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
- LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
LLCore::HttpHeaders::ptr_t &headers)
{
- return postFileAndYield(request, url, assetId, assetType,
+ return postFileAndSuspend(request, url, assetId, assetType,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
+ LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postJsonAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+
/// Execute a Put transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD putAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t headers)
+ {
+ return putAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return putJsonAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
/// Execute a Get transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD getAndYield(LLCore::HttpRequest::ptr_t request,
+ ///
+ LLSD getAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD getAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD getAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
- return getAndYield(request, url,
+ return getAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
- LLSD getRawAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD getRawAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
- return getRawAndYield(request, url,
+ return getRawAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
- LLSD getJsonAndYield(LLCore::HttpRequest::ptr_t request,
+ /// These methods have the same behavior as @getAndSuspend() however they are
+ /// expecting the server to return the results formatted in a JSON string.
+ /// On a successful GET call the JSON results will be converted into LLSD
+ /// before being returned to the caller.
+ LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD getJsonndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
- return getJsonAndYield(request, url,
+ return getJsonAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
@@ -451,10 +492,33 @@ public:
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD deleteAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t headers)
+ {
+ return deleteAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+ /// These methods have the same behavior as @deleteAndSuspend() however they are
+ /// expecting the server to return any results formatted in a JSON string.
+ /// On a successful DELETE call the JSON results will be converted into LLSD
+ /// before being returned to the caller.
+ LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t headers)
+ {
+ return deleteJsonAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
/// Execute a PATCH transaction on the supplied URL and yield execution of
@@ -462,15 +526,15 @@ public:
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD patchAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD patchAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
- return patchAndYield(request, url, body,
+ return patchAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
@@ -482,15 +546,15 @@ public:
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD copyAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD copyAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const std::string & dest,
LLCore::HttpHeaders::ptr_t &headers)
{
- return copyAndYield(request, url, dest,
+ return copyAndSuspend(request, url, dest,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
@@ -502,20 +566,20 @@ public:
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
- LLSD moveAndYield(LLCore::HttpRequest::ptr_t request,
+ LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
- LLSD moveAndYield(LLCore::HttpRequest::ptr_t &request,
+ LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const std::string & dest,
LLCore::HttpHeaders::ptr_t &headers)
{
- return moveAndYield(request, url, dest,
+ return moveAndSuspend(request, url, dest,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
///
- void cancelYieldingOperation();
+ void cancelSuspendedOperation();
static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults);
@@ -553,40 +617,45 @@ private:
HttpCoroHandler::ptr_t &handler);
void cleanState();
- LLSD postAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
- LLSD postAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
- LLSD putAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
- LLSD getAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLCore::BufferArray::ptr_t & rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpOptions::ptr_t &options,
LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
- LLSD deleteAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpOptions::ptr_t &options,
LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
- LLSD patchAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
- LLSD copyAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
- LLSD moveAndYield_(LLCore::HttpRequest::ptr_t &request,
+ LLSD moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
deleted file mode 100755
index ef28a4d211..0000000000
--- a/indra/llmessage/llcurl.cpp
+++ /dev/null
@@ -1,2042 +0,0 @@
-/**
- * @file llcurl.cpp
- * @author Zero / Donovan
- * @date 2006-10-15
- * @brief Implementation of wrapper around libcurl.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010-2013, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#if LL_WINDOWS
-#define SAFE_SSL 1
-#elif LL_DARWIN
-#define SAFE_SSL 1
-#else
-#define SAFE_SSL 1
-#endif
-
-#include "linden_common.h"
-
-#include "llcurl.h"
-
-#include <algorithm>
-#include <iomanip>
-#include <curl/curl.h>
-#if SAFE_SSL
-#include <openssl/crypto.h>
-#endif
-
-#include "llbufferstream.h"
-#include "llproxy.h"
-#include "llsdserialize.h"
-#include "llstl.h"
-#include "llstring.h"
-#include "llthread.h"
-#include "lltimer.h"
-
-//////////////////////////////////////////////////////////////////////////////
-/*
- The trick to getting curl to do keep-alives is to reuse the
- same easy handle for the requests. It appears that curl
- keeps a pool of connections alive for each easy handle, but
- doesn't share them between easy handles. Therefore it is
- important to keep a pool of easy handles and reuse them,
- rather than create and destroy them with each request. This
- code does this.
-
- Furthermore, it would behoove us to keep track of which
- hosts an easy handle was used for and pick an easy handle
- that matches the next request. This code does not current
- do this.
- */
-
-// *TODO: TSN remove the commented code from this file
-//////////////////////////////////////////////////////////////////////////////
-
-static const U32 EASY_HANDLE_POOL_SIZE = 5;
-static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
-static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation
-static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection
-
-//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
-
-// DEBUG //
-S32 gCurlEasyCount = 0;
-S32 gCurlMultiCount = 0;
-
-//////////////////////////////////////////////////////////////////////////////
-
-//static
-std::vector<LLMutex*> LLCurl::sSSLMutex;
-std::string LLCurl::sCAPath;
-std::string LLCurl::sCAFile;
-LLCurlThread* LLCurl::sCurlThread = NULL ;
-LLMutex* LLCurl::sHandleMutexp = NULL ;
-S32 LLCurl::sTotalHandles = 0 ;
-bool LLCurl::sNotQuitting = true;
-F32 LLCurl::sCurlRequestTimeOut = 120.f; //seonds
-S32 LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).
-CURL* LLCurl::sCurlTemplateStandardHandle = NULL;
-
-void check_curl_code(CURLcode code)
-{
- if (code != CURLE_OK)
- {
- // linux appears to throw a curl error once per session for a bad initialization
- // at a pretty random time (when enabling cookies).
- LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
- }
-}
-
-void check_curl_multi_code(CURLMcode code)
-{
- if (code != CURLM_OK)
- {
- // linux appears to throw a curl error once per session for a bad initialization
- // at a pretty random time (when enabling cookies).
- LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
- }
-}
-
-//static
-void LLCurl::setCAPath(const std::string& path)
-{
- sCAPath = path;
-}
-
-//static
-void LLCurl::setCAFile(const std::string& file)
-{
- sCAFile = file;
-}
-
-//static
-std::string LLCurl::getVersionString()
-{
- return std::string(curl_version());
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-LLCurl::Responder::Responder()
- : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
-{
-}
-
-LLCurl::Responder::~Responder()
-{
- LL_CHECK_MEMORY
-}
-
-// virtual
-void LLCurl::Responder::httpFailure()
-{
- LL_WARNS("curl") << dumpResponse() << LL_ENDL;
-}
-
-std::string LLCurl::Responder::dumpResponse() const
-{
- std::ostringstream s;
- s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] "
- << "[status:" << mStatus << "] "
- << "[reason:" << mReason << "] ";
-
- if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE))
- {
- s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] ";
- }
-
- s << "[content:" << mContent << "]";
-
- return s.str();
-}
-
-// virtual
-void LLCurl::Responder::httpSuccess()
-{
-}
-
-void LLCurl::Responder::setURL(const std::string& url)
-{
- mURL = url;
-}
-
-void LLCurl::Responder::successResult(const LLSD& content)
-{
- setResult(HTTP_OK, "", content);
- httpSuccess();
-}
-
-void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
-{
- setResult(status, reason, content);
- httpFailure();
-}
-
-void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
-{
- setResult(status, reason, content);
- httpCompleted();
-}
-
-void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
-{
- mStatus = status;
- mReason = reason;
- mContent = content;
-}
-
-void LLCurl::Responder::setHTTPMethod(EHTTPMethod method)
-{
- mHTTPMethod = method;
-}
-
-void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value)
-{
- mResponseHeaders[header] = value;
-}
-
-const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const
-{
- if (mResponseHeaders.has(header))
- {
- return mResponseHeaders[header].asStringRef();
- }
- static const std::string empty;
- return empty;
-}
-
-bool LLCurl::Responder::hasResponseHeader(const std::string& header) const
-{
- if (mResponseHeaders.has(header)) return true;
- return false;
-}
-
-// virtual
-void LLCurl::Responder::completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- LLBufferStream istr(channels, buffer.get());
- const bool emit_parse_errors = false;
-
- std::string debug_body("(empty)");
- bool parsed=true;
- if (EOF == istr.peek())
- {
- parsed=false;
- }
- // Try to parse body as llsd, no matter what 'content-type' says.
- else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors))
- {
- parsed=false;
- char body[1025];
- body[1024] = '\0';
- istr.seekg(0, std::ios::beg);
- istr.get(body,1024);
- if (strlen(body) > 0)
- {
- mContent = body;
- debug_body = body;
- }
- }
-
- // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
- if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE)))
- {
- LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] "
- << "(" << mReason << ") body: " << debug_body << LL_ENDL;
- }
-
- httpCompleted();
-}
-
-// virtual
-void LLCurl::Responder::httpCompleted()
-{
- if (isGoodStatus())
- {
- httpSuccess();
- }
- else
- {
- httpFailure();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-std::set<CURL*> LLCurl::Easy::sFreeHandles;
-std::set<CURL*> LLCurl::Easy::sActiveHandles;
-LLMutex* LLCurl::Easy::sHandleMutexp = NULL ;
-
-//static
-CURL* LLCurl::Easy::allocEasyHandle()
-{
- llassert(LLCurl::getCurlThread()) ;
-
- CURL* ret = NULL;
-
- LLMutexLock lock(sHandleMutexp) ;
-
- if (sFreeHandles.empty())
- {
- ret = LLCurl::newEasyHandle();
- }
- else
- {
- ret = *(sFreeHandles.begin());
- sFreeHandles.erase(ret);
- curl_easy_reset(ret);
- }
-
- if (ret)
- {
- sActiveHandles.insert(ret);
- }
-
- return ret;
-}
-
-//static
-void LLCurl::Easy::releaseEasyHandle(CURL* handle)
-{
- static const S32 MAX_NUM_FREE_HANDLES = 32 ;
-
- if (!handle)
- {
- return ; //handle allocation failed.
- //LL_ERRS() << "handle cannot be NULL!" << LL_ENDL;
- }
-
- LLMutexLock lock(sHandleMutexp) ;
- if (sActiveHandles.find(handle) != sActiveHandles.end())
- {
- LL_CHECK_MEMORY
- sActiveHandles.erase(handle);
- LL_CHECK_MEMORY
- if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES)
- {
- sFreeHandles.insert(handle);
- LL_CHECK_MEMORY
- }
- else
- {
- LLCurl::deleteEasyHandle(handle) ;
- LL_CHECK_MEMORY
- }
- }
- else
- {
- LL_ERRS() << "Invalid handle." << LL_ENDL;
- }
-}
-
-//static
-void LLCurl::Easy::deleteAllActiveHandles()
-{
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- for (std::set<CURL*>::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle)
- {
- CURL* curlHandle = *activeHandle;
- LLCurl::deleteEasyHandle(curlHandle);
- LL_CHECK_MEMORY
- }
-
- sFreeHandles.clear();
-}
-
-//static
-void LLCurl::Easy::deleteAllFreeHandles()
-{
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- for (std::set<CURL*>::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle)
- {
- CURL* curlHandle = *freeHandle;
- LLCurl::deleteEasyHandle(curlHandle);
- LL_CHECK_MEMORY
- }
-
- sFreeHandles.clear();
-}
-
-LLCurl::Easy::Easy()
- : mHeaders(NULL),
- mCurlEasyHandle(NULL)
-{
- mErrorBuffer[0] = 0;
-}
-
-LLCurl::Easy* LLCurl::Easy::getEasy()
-{
- Easy* easy = new Easy();
- easy->mCurlEasyHandle = allocEasyHandle();
-
- if (!easy->mCurlEasyHandle)
- {
- // this can happen if we have too many open files (fails in c-ares/ares_init.c)
- LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: "
- << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
- delete easy;
- return NULL;
- }
-
- // Enable a brief cache period for now. This was zero for the longest time
- // which caused some routers grief and generated unneeded traffic. For the
- // threaded resolver, we're using system resolution libraries and non-zero values
- // are preferred. The c-ares resolver is another matter and it might not
- // track server changes as well.
- CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_code(result);
- result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- check_curl_code(result);
-
- ++gCurlEasyCount;
- return easy;
-}
-
-LLCurl::Easy::~Easy()
-{
- releaseEasyHandle(mCurlEasyHandle);
- --gCurlEasyCount;
- curl_slist_free_all(mHeaders);
- LL_CHECK_MEMORY
- for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
- LL_CHECK_MEMORY
- if (mResponder && LLCurl::sNotQuitting) //aborted
- {
- // HTTP_REQUEST_TIME_OUT, timeout, abort
- // *TODO: This looks like improper use of the 408 status code.
- // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9
- // This status code should be returned by the *server* when:
- // "The client did not produce a request within the time that the server was prepared to wait."
- mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted.");
- mResponder->completedRaw(mChannels, mOutput);
- LL_CHECK_MEMORY
- }
- mResponder = NULL;
-}
-
-void LLCurl::Easy::resetState()
-{
- curl_easy_reset(mCurlEasyHandle);
-
- if (mHeaders)
- {
- curl_slist_free_all(mHeaders);
- mHeaders = NULL;
- }
-
- mRequest.str("");
- mRequest.clear();
-
- mOutput.reset();
-
- mInput.str("");
- mInput.clear();
-
- mErrorBuffer[0] = 0;
-
- mHeaderOutput.str("");
- mHeaderOutput.clear();
-}
-
-void LLCurl::Easy::setErrorBuffer()
-{
- setopt(CURLOPT_ERRORBUFFER, &mErrorBuffer);
-}
-
-const char* LLCurl::Easy::getErrorBuffer()
-{
- return mErrorBuffer;
-}
-
-void LLCurl::Easy::setCA()
-{
- if (!sCAPath.empty())
- {
- setoptString(CURLOPT_CAPATH, sCAPath);
- }
- if (!sCAFile.empty())
- {
- setoptString(CURLOPT_CAINFO, sCAFile);
- }
-}
-
-void LLCurl::Easy::setHeaders()
-{
- setopt(CURLOPT_HTTPHEADER, mHeaders);
-}
-
-void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
-{
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
-}
-
-S32 LLCurl::Easy::report(CURLcode code)
-{
- S32 responseCode = 0;
- std::string responseReason;
-
- if (code == CURLE_OK)
- {
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
- //*TODO: get reason from first line of mHeaderOutput
- }
- else
- {
- responseCode = HTTP_INTERNAL_ERROR;
- responseReason = strerror(code) + " : " + mErrorBuffer;
- setopt(CURLOPT_FRESH_CONNECT, TRUE);
- }
-
- if (mResponder)
- {
- mResponder->setResult(responseCode, responseReason);
- mResponder->completedRaw(mChannels, mOutput);
- mResponder = NULL;
- }
-
- resetState();
- return responseCode;
-}
-
-// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
-void LLCurl::Easy::setopt(CURLoption option, S32 value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-void LLCurl::Easy::setopt(CURLoption option, void* value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-void LLCurl::Easy::setopt(CURLoption option, char* value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-// Note: this copies the string so that the caller does not have to keep it around
-void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
-{
- char* tstring = new char[value.length()+1];
- strcpy(tstring, value.c_str());
- mStrings.push_back(tstring);
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
- check_curl_code(result);
-}
-
-void LLCurl::Easy::slist_append(const std::string& header, const std::string& value)
-{
- std::string pair(header);
- if (value.empty())
- {
- pair += ":";
- }
- else
- {
- pair += ": ";
- pair += value;
- }
- slist_append(pair.c_str());
-}
-
-void LLCurl::Easy::slist_append(const char* str)
-{
- if (str)
- {
- mHeaders = curl_slist_append(mHeaders, str);
- if (!mHeaders)
- {
- LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL;
- }
- }
-}
-
-size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- S32 n = size * nmemb;
- S32 startpos = (S32)easy->getInput().tellg();
- easy->getInput().seekg(0, std::ios::end);
- S32 endpos = (S32)easy->getInput().tellg();
- easy->getInput().seekg(startpos, std::ios::beg);
- S32 maxn = endpos - startpos;
- n = llmin(n, maxn);
- easy->getInput().read((char*)data, n);
-
- return n;
-}
-
-size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- S32 n = size * nmemb;
- easy->getOutput()->append(easy->getChannels().in(), (const U8*)data, n);
-
- return n;
-}
-
-size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- size_t n = size * nmemb;
- easy->getHeaderOutput().write((const char*)data, n);
-
- return n;
-}
-
-void LLCurl::Easy::prepRequest(const std::string& url,
- const std::vector<std::string>& headers,
- ResponderPtr responder, S32 time_out, bool post)
-{
- resetState();
-
- if (post) setoptString(CURLOPT_ENCODING, "");
-
- //setopt(CURLOPT_VERBOSE, 1); // useful for debugging
- setopt(CURLOPT_NOSIGNAL, 1);
- setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-
- // Set the CURL options for either Socks or HTTP proxy
- LLProxy::getInstance()->applyProxySettings(this);
-
- mOutput.reset(new LLBufferArray);
- mOutput->setThreaded(true);
- setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
- setopt(CURLOPT_WRITEDATA, (void*)this);
-
- setopt(CURLOPT_READFUNCTION, (void*)&curlReadCallback);
- setopt(CURLOPT_READDATA, (void*)this);
-
- setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback);
- setopt(CURLOPT_HEADERDATA, (void*)this);
-
- // Allow up to five redirects
- if (responder && responder->followRedir())
- {
- setopt(CURLOPT_FOLLOWLOCATION, 1);
- setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS);
- }
-
- setErrorBuffer();
- setCA();
-
- setopt(CURLOPT_SSL_VERIFYPEER, true);
-
- //don't verify host name so urls with scrubbed host names will work (improves DNS performance)
- setopt(CURLOPT_SSL_VERIFYHOST, 0);
- setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
- setopt(CURLOPT_CONNECTTIMEOUT, CURL_CONNECT_TIMEOUT);
-
- setoptString(CURLOPT_URL, url);
-
- mResponder = responder;
-
- if (!post)
- {
- // *TODO: Should this be set to 'Keep-Alive' ?
- slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive");
- slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300");
- // Accept and other headers
- for (std::vector<std::string>::const_iterator iter = headers.begin();
- iter != headers.end(); ++iter)
- {
- slist_append((*iter).c_str());
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////
-#if 1
-LLCurl::Multi::Multi(F32 idle_time_out)
- : mQueued(0),
- mErrorCount(0),
- mState(STATE_READY),
- mDead(FALSE),
- mValid(TRUE),
- mMutexp(NULL),
- mDeletionMutexp(NULL),
- mEasyMutexp(NULL)
-{
- mCurlMultiHandle = LLCurl::newMultiHandle();
- if (!mCurlMultiHandle)
- {
- LL_WARNS() << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
- mCurlMultiHandle = LLCurl::newMultiHandle();
- }
-
- //llassert_always(mCurlMultiHandle);
-
- if(mCurlMultiHandle)
- {
- if(LLCurl::getCurlThread()->getThreaded())
- {
- mMutexp = new LLMutex(NULL) ;
- mDeletionMutexp = new LLMutex(NULL) ;
- mEasyMutexp = new LLMutex(NULL) ;
- }
- LLCurl::getCurlThread()->addMulti(this) ;
-
- mIdleTimeOut = idle_time_out ;
- if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut)
- {
- mIdleTimeOut = LLCurl::sCurlRequestTimeOut ;
- }
-
- ++gCurlMultiCount;
-}
-}
-
-LLCurl::Multi::~Multi()
-{
- cleanup(true) ;
-
- delete mDeletionMutexp ;
- mDeletionMutexp = NULL ;
-}
-
-void LLCurl::Multi::cleanup(bool deleted)
-{
- if(!mCurlMultiHandle)
- {
- return ; //nothing to clean.
- }
- llassert_always(deleted || !mValid) ;
-
- LLMutexLock lock(mDeletionMutexp);
-
-
- // Clean up active
- for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
- iter != mEasyActiveList.end(); ++iter)
- {
- Easy* easy = *iter;
- LL_CHECK_MEMORY
- check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
- LL_CHECK_MEMORY
- if(deleted)
- {
- easy->mResponder = NULL ; //avoid triggering mResponder.
- LL_CHECK_MEMORY
- }
- delete easy;
- LL_CHECK_MEMORY
- }
- mEasyActiveList.clear();
- mEasyActiveMap.clear();
-
- LL_CHECK_MEMORY
-
- // Clean up freed
- for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
- mEasyFreeList.clear();
-
- LL_CHECK_MEMORY
-
- check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle));
- mCurlMultiHandle = NULL ;
-
- LL_CHECK_MEMORY
-
- delete mMutexp ;
- mMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- delete mEasyMutexp ;
- mEasyMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- mQueued = 0 ;
- mState = STATE_COMPLETED;
-
- --gCurlMultiCount;
-
- return ;
-}
-
-void LLCurl::Multi::lock()
-{
- if(mMutexp)
- {
- mMutexp->lock() ;
- }
-}
-
-void LLCurl::Multi::unlock()
-{
- if(mMutexp)
- {
- mMutexp->unlock() ;
- }
-}
-
-void LLCurl::Multi::markDead()
-{
- {
- LLMutexLock lock(mDeletionMutexp) ;
-
- if(mCurlMultiHandle != NULL)
- {
- mDead = TRUE ;
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ;
-
- return;
- }
- }
-
- //not valid, delete it.
- delete this;
-}
-
-void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state)
-{
- lock() ;
- mState = state ;
- unlock() ;
-
- if(mState == STATE_READY)
- {
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_NORMAL) ;
- }
-}
-
-LLCurl::Multi::ePerformState LLCurl::Multi::getState()
-{
- return mState;
-}
-
-bool LLCurl::Multi::isCompleted()
-{
- return STATE_COMPLETED == getState() ;
-}
-
-bool LLCurl::Multi::waitToComplete()
-{
- if(!isValid())
- {
- return true ;
- }
-
- if(!mMutexp) //not threaded
- {
- doPerform() ;
- return true ;
- }
-
- bool completed = (STATE_COMPLETED == mState) ;
- if(!completed)
- {
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ;
- }
-
- return completed;
-}
-
-CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
-{
- LLMutexLock lock(mMutexp) ;
-
- CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
- return curlmsg;
-}
-
-//return true if dead
-bool LLCurl::Multi::doPerform()
-{
- LLMutexLock lock(mDeletionMutexp) ;
-
- bool dead = mDead ;
-
- if(mDead)
- {
- setState(STATE_COMPLETED);
- mQueued = 0 ;
- }
- else if(getState() != STATE_COMPLETED)
- {
- setState(STATE_PERFORMING);
-
- S32 q = 0;
- for (S32 call_count = 0;
- call_count < MULTI_PERFORM_CALL_REPEAT;
- call_count++)
- {
- LLMutexLock lock(mMutexp) ;
-
- //WARNING: curl_multi_perform will block for many hundreds of milliseconds
- // NEVER call this from the main thread, and NEVER allow the main thread to
- // wait on a mutex held by this thread while curl_multi_perform is executing
- CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
- if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
- {
- check_curl_multi_code(code);
-
- break;
- }
- }
-
- mQueued = q;
- setState(STATE_COMPLETED) ;
- mIdleTimer.reset() ;
- }
- else if(!mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
- {
- dead = true ;
- }
- else if(mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut - 1.f) //idle for too long, mark it invalid.
- {
- mValid = FALSE ;
- }
-
- return dead ;
-}
-
-S32 LLCurl::Multi::process()
-{
- if(!isValid())
- {
- return 0 ;
- }
-
- waitToComplete() ;
-
- if (getState() != STATE_COMPLETED)
- {
- return 0;
- }
-
- CURLMsg* msg;
- int msgs_in_queue;
-
- S32 processed = 0;
- while ((msg = info_read(&msgs_in_queue)))
- {
- ++processed;
- if (msg->msg == CURLMSG_DONE)
- {
- S32 response = 0;
- Easy* easy = NULL ;
-
- {
- LLMutexLock lock(mEasyMutexp) ;
- easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
- if (iter != mEasyActiveMap.end())
- {
- easy = iter->second;
- }
- }
-
- if(easy)
- {
- response = easy->report(msg->data.result);
- removeEasy(easy);
- }
- else
- {
- response = HTTP_INTERNAL_ERROR;
- //*TODO: change to LL_WARNS()
- LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL;
- }
- if (response >= 400)
- {
- // failure of some sort, inc mErrorCount for debugging and flagging multi for destruction
- ++mErrorCount;
- }
- }
- }
-
- setState(STATE_READY);
-
- return processed;
-}
-
-LLCurl::Easy* LLCurl::Multi::allocEasy()
-{
- Easy* easy = 0;
-
- if (mEasyFreeList.empty())
- {
- easy = Easy::getEasy();
- }
- else
- {
- LLMutexLock lock(mEasyMutexp) ;
- easy = *(mEasyFreeList.begin());
- mEasyFreeList.erase(easy);
- }
- if (easy)
- {
- LLMutexLock lock(mEasyMutexp) ;
- mEasyActiveList.insert(easy);
- mEasyActiveMap[easy->getCurlHandle()] = easy;
- }
- return easy;
-}
-
-bool LLCurl::Multi::addEasy(Easy* easy)
-{
- LLMutexLock lock(mMutexp) ;
- CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
- check_curl_multi_code(mcode);
- //if (mcode != CURLM_OK)
- //{
- // LL_WARNS() << "Curl Error: " << curl_multi_strerror(mcode) << LL_ENDL;
- // return false;
- //}
- return true;
-}
-
-void LLCurl::Multi::easyFree(Easy* easy)
-{
- if(mEasyMutexp)
- {
- mEasyMutexp->lock() ;
- }
-
- mEasyActiveList.erase(easy);
- mEasyActiveMap.erase(easy->getCurlHandle());
-
- if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE)
- {
- mEasyFreeList.insert(easy);
-
- if(mEasyMutexp)
- {
- mEasyMutexp->unlock() ;
- }
-
- easy->resetState();
- }
- else
- {
- if(mEasyMutexp)
- {
- mEasyMutexp->unlock() ;
- }
- delete easy;
- }
-}
-
-void LLCurl::Multi::removeEasy(Easy* easy)
-{
- {
- LLMutexLock lock(mMutexp) ;
- check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
- }
- easyFree(easy);
-}
-
-#endif
-//------------------------------------------------------------
-//LLCurlThread
-LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
- LLQueuedThread::QueuedRequest(handle, LLQueuedThread::PRIORITY_NORMAL, FLAG_AUTO_COMPLETE),
- mMulti(multi),
- mCurlThread(curl_thread)
-{
-}
-
-LLCurlThread::CurlRequest::~CurlRequest()
-{
- if(mMulti)
- {
- mCurlThread->deleteMulti(mMulti) ;
- mMulti = NULL ;
- }
-}
-
-bool LLCurlThread::CurlRequest::processRequest()
-{
- bool completed = true ;
- if(mMulti)
- {
- completed = mCurlThread->doMultiPerform(mMulti) ;
-
- if(!completed)
- {
- setPriority(LLQueuedThread::PRIORITY_LOW) ;
- }
- }
-
- return completed ;
-}
-
-void LLCurlThread::CurlRequest::finishRequest(bool completed)
-{
- if(mMulti->isDead())
- {
- mCurlThread->deleteMulti(mMulti) ;
- }
- else
- {
- mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request.
- }
-
- mMulti = NULL ;
-}
-
-LLCurlThread::LLCurlThread(bool threaded) :
- LLQueuedThread("curlthread", threaded)
-{
-}
-
-//virtual
-LLCurlThread::~LLCurlThread()
-{
-}
-
-S32 LLCurlThread::update(F32 max_time_ms)
-{
- return LLQueuedThread::update(max_time_ms);
-}
-
-void LLCurlThread::addMulti(LLCurl::Multi* multi)
-{
- multi->mHandle = generateHandle() ;
-
- CurlRequest* req = new CurlRequest(multi->mHandle, multi, this) ;
-
- if (!addRequest(req))
- {
- LL_WARNS() << "curl request added when the thread is quitted" << LL_ENDL;
- }
-}
-
-void LLCurlThread::killMulti(LLCurl::Multi* multi)
-{
- if(!multi)
- {
- return ;
- }
-
-
- multi->markDead() ;
-}
-
-//private
-bool LLCurlThread::doMultiPerform(LLCurl::Multi* multi)
-{
- return multi->doPerform() ;
-}
-
-//private
-void LLCurlThread::deleteMulti(LLCurl::Multi* multi)
-{
- delete multi ;
-}
-
-//private
-void LLCurlThread::cleanupMulti(LLCurl::Multi* multi)
-{
- multi->cleanup() ;
- if(multi->isDead()) //check if marked dead during cleaning up.
- {
- deleteMulti(multi) ;
- }
-}
-
-//------------------------------------------------------------
-
-//static
-std::string LLCurl::strerror(CURLcode errorcode)
-{
- return std::string(curl_easy_strerror(errorcode));
-}
-
-////////////////////////////////////////////////////////////////////////////
-// For generating a simple request for data
-// using one multi and one easy per request
-
-// LLCurlRequest::LLCurlRequest() :
-// mActiveMulti(NULL),
-// mActiveRequestCount(0)
-// {
-// mProcessing = FALSE;
-// }
-//
-// LLCurlRequest::~LLCurlRequest()
-// {
-// //stop all Multi handle background threads
-// for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
-// {
-// LLCurl::getCurlThread()->killMulti(*iter) ;
-// }
-// mMultiSet.clear() ;
-// }
-//
-// void LLCurlRequest::addMulti()
-// {
-// LLCurl::Multi* multi = new LLCurl::Multi();
-// if(!multi->isValid())
-// {
-// LLCurl::getCurlThread()->killMulti(multi) ;
-// mActiveMulti = NULL ;
-// mActiveRequestCount = 0 ;
-// return;
-// }
-//
-// mMultiSet.insert(multi);
-// mActiveMulti = multi;
-// mActiveRequestCount = 0;
-// }
-//
-// LLCurl::Easy* LLCurlRequest::allocEasy()
-// {
-// if (!mActiveMulti ||
-// mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT ||
-// mActiveMulti->mErrorCount > 0)
-// {
-// addMulti();
-// }
-// if(!mActiveMulti)
-// {
-// return NULL ;
-// }
-//
-// //llassert_always(mActiveMulti);
-// ++mActiveRequestCount;
-// LLCurl::Easy* easy = mActiveMulti->allocEasy();
-// return easy;
-// }
-//
-// bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
-// {
-// llassert_always(mActiveMulti);
-//
-// if (mProcessing)
-// {
-// LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
-// }
-// bool res = mActiveMulti->addEasy(easy);
-// return res;
-// }
-//
-// void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
-// {
-// getByteRange(url, headers_t(), 0, -1, responder);
-// }
-//
-// // Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
-// // the remainder of the file if not.
-// bool LLCurlRequest::getByteRange(const std::string& url,
-// const headers_t& headers,
-// S32 offset, S32 length,
-// LLCurl::ResponderPtr responder)
-// {
-// llassert(LLCurl::sNotQuitting);
-// LLCurl::Easy* easy = allocEasy();
-// if (!easy)
-// {
-// return false;
-// }
-// easy->prepRequest(url, headers, responder);
-// easy->setopt(CURLOPT_HTTPGET, 1);
-// if (length > 0)
-// {
-// std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
-// easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
-// }
-// else if (offset > 0)
-// {
-// std::string range = llformat("bytes=%d-", offset);
-// easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
-// }
-// easy->setHeaders();
-// bool res = addEasy(easy);
-// return res;
-// }
-//
-// bool LLCurlRequest::post(const std::string& url,
-// const headers_t& headers,
-// const LLSD& data,
-// LLCurl::ResponderPtr responder, S32 time_out)
-// {
-// llassert(LLCurl::sNotQuitting);
-// LLCurl::Easy* easy = allocEasy();
-// if (!easy)
-// {
-// return false;
-// }
-// easy->prepRequest(url, headers, responder, time_out);
-//
-// LLSDSerialize::toXML(data, easy->getInput());
-// S32 bytes = easy->getInput().str().length();
-//
-// easy->setopt(CURLOPT_POST, 1);
-// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
-// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-//
-// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
-// easy->setHeaders();
-//
-// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
-// bool res = addEasy(easy);
-// return res;
-// }
-//
-// bool LLCurlRequest::post(const std::string& url,
-// const headers_t& headers,
-// const std::string& data,
-// LLCurl::ResponderPtr responder, S32 time_out)
-// {
-// llassert(LLCurl::sNotQuitting);
-// LLCurl::Easy* easy = allocEasy();
-// if (!easy)
-// {
-// return false;
-// }
-// easy->prepRequest(url, headers, responder, time_out);
-//
-// easy->getInput().write(data.data(), data.size());
-// S32 bytes = easy->getInput().str().length();
-//
-// easy->setopt(CURLOPT_POST, 1);
-// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
-// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-//
-// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
-// easy->setHeaders();
-//
-// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
-// bool res = addEasy(easy);
-// return res;
-// }
-//
-// // Note: call once per frame
-// S32 LLCurlRequest::process()
-// {
-// S32 res = 0;
-//
-// mProcessing = TRUE;
-// for (curlmulti_set_t::iterator iter = mMultiSet.begin();
-// iter != mMultiSet.end(); )
-// {
-// curlmulti_set_t::iterator curiter = iter++;
-// LLCurl::Multi* multi = *curiter;
-//
-// if(!multi->isValid())
-// {
-// if(multi == mActiveMulti)
-// {
-// mActiveMulti = NULL ;
-// mActiveRequestCount = 0 ;
-// }
-// mMultiSet.erase(curiter) ;
-// LLCurl::getCurlThread()->killMulti(multi) ;
-// continue ;
-// }
-//
-// S32 tres = multi->process();
-// res += tres;
-// if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
-// {
-// mMultiSet.erase(curiter);
-// LLCurl::getCurlThread()->killMulti(multi);
-// }
-// }
-// mProcessing = FALSE;
-// return res;
-// }
-//
-// S32 LLCurlRequest::getQueued()
-// {
-// S32 queued = 0;
-// for (curlmulti_set_t::iterator iter = mMultiSet.begin();
-// iter != mMultiSet.end(); )
-// {
-// curlmulti_set_t::iterator curiter = iter++;
-// LLCurl::Multi* multi = *curiter;
-//
-// if(!multi->isValid())
-// {
-// if(multi == mActiveMulti)
-// {
-// mActiveMulti = NULL ;
-// mActiveRequestCount = 0 ;
-// }
-// LLCurl::getCurlThread()->killMulti(multi);
-// mMultiSet.erase(curiter) ;
-// continue ;
-// }
-//
-// queued += multi->mQueued;
-// if (multi->getState() != LLCurl::Multi::STATE_READY)
-// {
-// ++queued;
-// }
-// }
-// return queued;
-// }
-
-// LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :
-// LLCurlRequest(),
-// mConcurrency(concurrency),
-// mInQueue(0),
-// mMutex(NULL),
-// mHandleCounter(1),
-// mTotalIssuedRequests(0),
-// mTotalReceivedBits(0)
-// {
-// mGlobalTimer.reset();
-// }
-//
-// LLCurlTextureRequest::~LLCurlTextureRequest()
-// {
-// mRequestMap.clear();
-//
-// for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
-// {
-// delete *iter;
-// }
-// mCachedRequests.clear();
-// }
-//
-// //return 0: success
-// // > 0: cached handle
-// U32 LLCurlTextureRequest::getByteRange(const std::string& url,
-// const headers_t& headers,
-// S32 offset, S32 length, U32 pri,
-// LLCurl::ResponderPtr responder, F32 delay_time)
-// {
-// U32 ret_val = 0;
-// bool success = false;
-//
-// if(mInQueue < mConcurrency && delay_time < 0.f)
-// {
-// success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);
-// }
-//
-// LLMutexLock lock(&mMutex);
-//
-// if(success)
-// {
-// mInQueue++;
-// mTotalIssuedRequests++;
-// }
-// else
-// {
-// request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
-// if(delay_time > 0.f)
-// {
-// request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
-// }
-//
-// mCachedRequests.insert(request);
-// mRequestMap[mHandleCounter] = request;
-// ret_val = mHandleCounter;
-// mHandleCounter++;
-//
-// if(!mHandleCounter)
-// {
-// mHandleCounter = 1;
-// }
-// }
-//
-// return ret_val;
-// }
-//
-// void LLCurlTextureRequest::completeRequest(S32 received_bytes)
-// {
-// LLMutexLock lock(&mMutex);
-//
-// llassert_always(mInQueue > 0);
-//
-// mInQueue--;
-// mTotalReceivedBits += received_bytes * 8;
-// }
-//
-// void LLCurlTextureRequest::nextRequests()
-// {
-// if(mCachedRequests.empty() || mInQueue >= mConcurrency)
-// {
-// return;
-// }
-//
-// F32 cur_time = mGlobalTimer.getElapsedTimeF32();
-//
-// req_queue_t::iterator iter;
-// {
-// LLMutexLock lock(&mMutex);
-// iter = mCachedRequests.begin();
-// }
-// while(1)
-// {
-// request_t* request = *iter;
-// if(request->mStartTime < cur_time)
-// {
-// if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
-// {
-// break;
-// }
-//
-// LLMutexLock lock(&mMutex);
-// ++iter;
-// mInQueue++;
-// mTotalIssuedRequests++;
-// mCachedRequests.erase(request);
-// mRequestMap.erase(request->mHandle);
-// delete request;
-//
-// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
-// {
-// break;
-// }
-// }
-// else
-// {
-// LLMutexLock lock(&mMutex);
-// ++iter;
-// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
-// {
-// break;
-// }
-// }
-// }
-//
-// return;
-// }
-//
-// void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
-// {
-// if(!handle)
-// {
-// return;
-// }
-//
-// LLMutexLock lock(&mMutex);
-//
-// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
-// if(iter != mRequestMap.end())
-// {
-// request_t* req = iter->second;
-//
-// if(req->mPriority != pri)
-// {
-// mCachedRequests.erase(req);
-// req->mPriority = pri;
-// mCachedRequests.insert(req);
-// }
-// }
-// }
-//
-// void LLCurlTextureRequest::removeRequest(U32 handle)
-// {
-// if(!handle)
-// {
-// return;
-// }
-//
-// LLMutexLock lock(&mMutex);
-//
-// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
-// if(iter != mRequestMap.end())
-// {
-// request_t* req = iter->second;
-// mRequestMap.erase(iter);
-// mCachedRequests.erase(req);
-// delete req;
-// }
-// }
-//
-// bool LLCurlTextureRequest::isWaiting(U32 handle)
-// {
-// if(!handle)
-// {
-// return false;
-// }
-//
-// LLMutexLock lock(&mMutex);
-// return mRequestMap.find(handle) != mRequestMap.end();
-// }
-//
-// U32 LLCurlTextureRequest::getTotalReceivedBits()
-// {
-// LLMutexLock lock(&mMutex);
-//
-// U32 bits = mTotalReceivedBits;
-// mTotalReceivedBits = 0;
-// return bits;
-// }
-//
-// U32 LLCurlTextureRequest::getTotalIssuedRequests()
-// {
-// LLMutexLock lock(&mMutex);
-// return mTotalIssuedRequests;
-// }
-//
-// S32 LLCurlTextureRequest::getNumRequests()
-// {
-// LLMutexLock lock(&mMutex);
-// return mInQueue;
-// }
-
-////////////////////////////////////////////////////////////////////////////
-// For generating one easy request
-// associated with a single multi request
-
-LLCurlEasyRequest::LLCurlEasyRequest()
- : mRequestSent(false),
- mResultReturned(false)
-{
- mMulti = new LLCurl::Multi();
-
- if(mMulti->isValid())
- {
- mEasy = mMulti->allocEasy();
- if (mEasy)
- {
- mEasy->setErrorBuffer();
- mEasy->setCA();
- // Set proxy settings if configured to do so.
- LLProxy::getInstance()->applyProxySettings(mEasy);
- }
-}
- else
- {
- LLCurl::getCurlThread()->killMulti(mMulti) ;
- mEasy = NULL ;
- mMulti = NULL ;
- }
-}
-
-LLCurlEasyRequest::~LLCurlEasyRequest()
-{
- LLCurl::getCurlThread()->killMulti(mMulti) ;
-}
-
-void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(option, value);
- }
-}
-
-void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)
-{
- if (isValid() && mEasy)
- {
- mEasy->setoptString(option, value);
- }
-}
-
-void LLCurlEasyRequest::setPost(char* postdata, S32 size)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_POST, 1);
- mEasy->setopt(CURLOPT_POSTFIELDS, postdata);
- mEasy->setopt(CURLOPT_POSTFIELDSIZE, size);
- }
-}
-
-void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER
- }
-}
-
-void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_WRITEDATA, userdata);
- }
-}
-
-void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_READDATA, userdata);
- }
-}
-
-void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
- }
-}
-
-void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value)
-{
- if (isValid() && mEasy)
- {
- mEasy->slist_append(header, value);
- }
-}
-
-void LLCurlEasyRequest::slist_append(const char* str)
-{
- if (isValid() && mEasy)
- {
- mEasy->slist_append(str);
- }
-}
-
-void LLCurlEasyRequest::sendRequest(const std::string& url)
-{
- llassert_always(!mRequestSent);
- mRequestSent = true;
- LL_DEBUGS() << url << LL_ENDL;
- if (isValid() && mEasy)
- {
- mEasy->setHeaders();
- mEasy->setoptString(CURLOPT_URL, url);
- mMulti->addEasy(mEasy);
- }
-}
-
-void LLCurlEasyRequest::requestComplete()
-{
- llassert_always(mRequestSent);
- mRequestSent = false;
- if (isValid() && mEasy)
- {
- mMulti->removeEasy(mEasy);
- }
-}
-
-// Usage: Call getRestult until it returns false (no more messages)
-bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
-{
- if(!isValid())
- {
- return false ;
- }
- if (!mMulti->isCompleted())
- { //we're busy, try again later
- return false;
- }
- mMulti->setState(LLCurl::Multi::STATE_READY) ;
-
- if (!mEasy)
- {
- // Special case - we failed to initialize a curl_easy (can happen if too many open files)
- // Act as though the request failed to connect
- if (mResultReturned)
- {
- return false;
- }
- else
- {
- *result = CURLE_FAILED_INIT;
- mResultReturned = true;
- return true;
- }
- }
- // In theory, info_read might return a message with a status other than CURLMSG_DONE
- // In practice for all messages returned, msg == CURLMSG_DONE
- // Ignore other messages just in case
- while(1)
- {
- S32 q;
- CURLMsg* curlmsg = info_read(&q, info);
- if (curlmsg)
- {
- if (curlmsg->msg == CURLMSG_DONE)
- {
- *result = curlmsg->data.result;
- return true;
- }
- // else continue
- }
- else
- {
- return false;
- }
- }
-}
-
-// private
-CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)
-{
- if (mEasy)
- {
- CURLMsg* curlmsg = mMulti->info_read(q);
- if (curlmsg && curlmsg->msg == CURLMSG_DONE)
- {
- if (info)
- {
- mEasy->getTransferInfo(info);
- }
- }
- return curlmsg;
- }
- return NULL;
-}
-
-std::string LLCurlEasyRequest::getErrorString()
-{
- return isValid() && mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-#if SAFE_SSL
-//static
-void LLCurl::ssl_locking_callback(int mode, int type, const char *file, int line)
-{
- if (mode & CRYPTO_LOCK)
- {
- LLCurl::sSSLMutex[type]->lock();
- }
- else
- {
- LLCurl::sSSLMutex[type]->unlock();
- }
-}
-
-//static
-unsigned long LLCurl::ssl_thread_id(void)
-{
- return LLThread::currentID();
-}
-#endif
-
-void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)
-{
- sCurlRequestTimeOut = curl_reuest_timeout ; //seconds
- sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined).
-
- // Do not change this "unless you are familiar with and mean to control
- // internal operations of libcurl"
- // - http://curl.haxx.se/libcurl/c/curl_global_init.html
- CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
-
- check_curl_code(code);
-
-#if SAFE_SSL
- S32 mutex_count = CRYPTO_num_locks();
- for (S32 i=0; i<mutex_count; i++)
- {
- sSSLMutex.push_back(new LLMutex(NULL));
- }
- CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
- CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
-#endif
-
- sCurlThread = new LLCurlThread(multi_threaded) ;
- if(multi_threaded)
- {
- sHandleMutexp = new LLMutex(NULL) ;
- Easy::sHandleMutexp = new LLMutex(NULL) ;
- }
-}
-
-void LLCurl::cleanupClass()
-{
- sNotQuitting = false; //set quitting
-
- //shut down curl thread
- while(1)
- {
- if(!sCurlThread->update(1)) //finish all tasks
- {
- break ;
- }
- }
- LL_CHECK_MEMORY
- sCurlThread->shutdown() ;
- LL_CHECK_MEMORY
- delete sCurlThread ;
- sCurlThread = NULL ;
- LL_CHECK_MEMORY
-
-#if SAFE_SSL
- CRYPTO_set_locking_callback(NULL);
- for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
- sSSLMutex.clear();
-#endif
-
- LL_CHECK_MEMORY
- Easy::deleteAllFreeHandles();
- LL_CHECK_MEMORY
- Easy::deleteAllActiveHandles();
- LL_CHECK_MEMORY
-
- // Free the template easy handle
- curl_easy_cleanup(sCurlTemplateStandardHandle);
- sCurlTemplateStandardHandle = NULL;
- LL_CHECK_MEMORY
-
- delete Easy::sHandleMutexp ;
- Easy::sHandleMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- delete sHandleMutexp ;
- sHandleMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- // removed as per https://jira.secondlife.com/browse/SH-3115
- //llassert(Easy::sActiveHandles.empty());
-}
-
-//static
-CURLM* LLCurl::newMultiHandle()
-{
- llassert(sNotQuitting);
-
- LLMutexLock lock(sHandleMutexp) ;
-
- if(sTotalHandles + 1 > sMaxHandles)
- {
- LL_WARNS() << "no more handles available." << LL_ENDL ;
- return NULL ; //failed
- }
- sTotalHandles++;
-
- CURLM* ret = curl_multi_init() ;
- if(!ret)
- {
- LL_WARNS() << "curl_multi_init failed." << LL_ENDL ;
- }
-
- return ret ;
-}
-
-//static
-CURLMcode LLCurl::deleteMultiHandle(CURLM* handle)
-{
- if(handle)
- {
- LLMutexLock lock(sHandleMutexp) ;
- sTotalHandles-- ;
- return curl_multi_cleanup(handle) ;
- }
- return CURLM_OK ;
-}
-
-//static
-CURL* LLCurl::newEasyHandle()
-{
- llassert(sNotQuitting);
- LLMutexLock lock(sHandleMutexp) ;
-
- if(sTotalHandles + 1 > sMaxHandles)
- {
- LL_WARNS() << "no more handles available." << LL_ENDL ;
- return NULL ; //failed
- }
- sTotalHandles++;
-
- CURL* ret = createStandardCurlHandle();
- if(!ret)
- {
- LL_WARNS() << "failed to create curl handle." << LL_ENDL ;
- }
-
- return ret ;
-}
-
-//static
-void LLCurl::deleteEasyHandle(CURL* handle)
-{
- if(handle)
- {
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- curl_easy_cleanup(handle) ;
- LL_CHECK_MEMORY
- sTotalHandles-- ;
- }
-}
-
-const unsigned int LLCurl::MAX_REDIRECTS = 5;
-
-// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
-void LLCurlFF::check_easy_code(CURLcode code)
-{
- check_curl_code(code);
-}
-// void LLCurlFF::check_multi_code(CURLMcode code)
-// {
-// check_curl_multi_code(code);
-// }
-
-
-// Static
-CURL* LLCurl::createStandardCurlHandle()
-{
- if (sCurlTemplateStandardHandle == NULL)
- { // Late creation of the template curl handle
- sCurlTemplateStandardHandle = curl_easy_init();
- if (sCurlTemplateStandardHandle == NULL)
- {
- LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
- }
- else
- {
- CURLcode result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOSIGNAL, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOPROGRESS, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_ENCODING, "");
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_AUTOREFERER, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_FOLLOWLOCATION, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYPEER, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYHOST, 0);
- check_curl_code(result);
-
- // The Linksys WRT54G V5 router has an issue with frequent
- // DNS lookups from LAN machines. If they happen too often,
- // like for every HTTP request, the router gets annoyed after
- // about 700 or so requests and starts issuing TCP RSTs to
- // new connections. Reuse the DNS lookups for even a few
- // seconds and no RSTs.
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_code(result);
- }
- }
-
- return curl_easy_duphandle(sCurlTemplateStandardHandle);
-}
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
deleted file mode 100755
index 06b3ce45e1..0000000000
--- a/indra/llmessage/llcurl.h
+++ /dev/null
@@ -1,462 +0,0 @@
-/**
- * @file llcurl.h
- * @author Zero / Donovan
- * @date 2006-10-15
- * @brief A wrapper around libcurl.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLCURL_H
-#define LL_LLCURL_H
-
-#include "linden_common.h"
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <boost/intrusive_ptr.hpp>
-#include <curl/curl.h> // TODO: remove dependency
-
-#include "llbuffer.h"
-#include "llhttpconstants.h"
-#include "lliopipe.h"
-#include "llsd.h"
-#include "llqueuedthread.h"
-#include "llframetimer.h"
-#include "llpointer.h"
-#include "llsingleton.h"
-
-class LLMutex;
-class LLCurlThread;
-
-// For whatever reason, this is not typedef'd in curl.h
-typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
-
-class LLCurl
-{
- LOG_CLASS(LLCurl);
-
-public:
- class Easy;
- class Multi;
-
- struct TransferInfo
- {
- TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
- F64 mSizeDownload;
- F64 mTotalTime;
- F64 mSpeedDownload;
- };
-
- class Responder : public LLThreadSafeRefCount
- {
- //LOG_CLASS(Responder);
- public:
-
- Responder();
- virtual ~Responder();
-
- virtual bool followRedir()
- {
- return false;
- }
-
- /**
- * @brief return true if the status code indicates success.
- */
- bool isGoodStatus() const { return isHttpGoodStatus(mStatus); }
-
- S32 getStatus() const { return mStatus; }
- const std::string& getReason() const { return mReason; }
- const LLSD& getContent() const { return mContent; }
- bool hasResponseHeader(const std::string& header) const;
- const std::string& getResponseHeader(const std::string& header) const;
- const LLSD& getResponseHeaders() const { return mResponseHeaders; }
- const std::string& getURL() const { return mURL; }
- EHTTPMethod getHTTPMethod() const { return mHTTPMethod; }
-
- // This formats response information for use in log spam. Includes content spam.
- std::string dumpResponse() const;
-
- // Allows direct triggering of success/error with different results.
- void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
- void successResult(const LLSD& content);
- void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
-
- // The default implementation will try to parse body content as an LLSD, however
- // it should not spam about parsing failures unless the server sent a
- // Content-Type: application/llsd+xml header.
- virtual void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
- /**< Override point for clients that may want to use this
- class when the response is some other format besides LLSD
- */
-
-
- // The http* methods are not public since these should be triggered internally
- // after status, reason, content, etc have been set.
- // If you need to trigger a completion method, use the *Result methods, above.
- protected:
- // These methods are the preferred way to process final results.
- // By default, when one of these is called the following information will be resolved:
- // * HTTP status code - getStatus()
- // * Reason string - getReason()
- // * Content - getContent()
- // * Response Headers - getResponseHeaders()
-
- // By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code.
- virtual void httpSuccess();
- //< called by completed for good status codes.
-
- // By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code.
- virtual void httpFailure();
- //< called by httpCompleted() on bad status
-
- // httpCompleted does not generally need to be overridden, unless
- // you don't care about the status code (which determine httpFailure or httpSuccess)
- // or if you want to re-interpret what a 'good' vs' bad' status code is.
- virtual void httpCompleted();
- /**< The default implementation calls
- either:
- * httpSuccess(), or
- * httpFailure()
- */
-
- public:
- void setHTTPMethod(EHTTPMethod method);
- void setURL(const std::string& url);
- void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
- void setResponseHeader(const std::string& header, const std::string& value);
-
- private:
- // These can be accessed by the get* methods. Treated as 'read-only' during completion handlers.
- EHTTPMethod mHTTPMethod;
- std::string mURL;
- LLSD mResponseHeaders;
-
- protected:
- // These should also generally be treated as 'read-only' during completion handlers
- // and should be accessed by the get* methods. The exception to this rule would
- // be when overriding the completedRaw method in preparation for calling httpCompleted().
- S32 mStatus;
- std::string mReason;
- LLSD mContent;
- };
- typedef LLPointer<Responder> ResponderPtr;
-
-
- /**
- * @ brief Set certificate authority file used to verify HTTPS certs.
- */
- static void setCAFile(const std::string& file);
-
- /**
- * @ brief Set certificate authority path used to verify HTTPS certs.
- */
- static void setCAPath(const std::string& path);
-
- /**
- * @ brief Return human-readable string describing libcurl version.
- */
- static std::string getVersionString();
-
- /**
- * @ brief Get certificate authority file used to verify HTTPS certs.
- */
- static const std::string& getCAFile() { return sCAFile; }
-
- /**
- * @ brief Get certificate authority path used to verify HTTPS certs.
- */
- static const std::string& getCAPath() { return sCAPath; }
-
- /**
- * @ brief Initialize LLCurl class
- */
- static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);
-
- /**
- * @ brief Cleanup LLCurl class
- */
- static void cleanupClass();
-
- /**
- * @ brief curl error code -> string
- */
- static std::string strerror(CURLcode errorcode);
-
- // For OpenSSL callbacks
- static std::vector<LLMutex*> sSSLMutex;
-
- // OpenSSL callbacks
- static void ssl_locking_callback(int mode, int type, const char *file, int line);
- static unsigned long ssl_thread_id(void);
-
- static LLCurlThread* getCurlThread() { return sCurlThread ;}
-
- static CURLM* newMultiHandle() ;
- static CURLMcode deleteMultiHandle(CURLM* handle) ;
- static CURL* newEasyHandle() ;
- static void deleteEasyHandle(CURL* handle) ;
-
- static CURL* createStandardCurlHandle();
-
-private:
- static std::string sCAPath;
- static std::string sCAFile;
- static const unsigned int MAX_REDIRECTS;
- static LLCurlThread* sCurlThread;
-
- static LLMutex* sHandleMutexp ;
- static S32 sTotalHandles ;
- static S32 sMaxHandles;
- static CURL* sCurlTemplateStandardHandle;
-public:
- static bool sNotQuitting;
- static F32 sCurlRequestTimeOut;
-};
-
-class LLCurl::Easy
-{
- LOG_CLASS(Easy);
-
-private:
- Easy();
-
-public:
- static Easy* getEasy();
- ~Easy();
-
- CURL* getCurlHandle() const { return mCurlEasyHandle; }
-
- void setErrorBuffer();
- void setCA();
-
- void setopt(CURLoption option, S32 value);
- // These assume the setter does not free value!
- void setopt(CURLoption option, void* value);
- void setopt(CURLoption option, char* value);
- // Copies the string so that it is guaranteed to stick around
- void setoptString(CURLoption option, const std::string& value);
-
- void slist_append(const std::string& header, const std::string& value);
- void slist_append(const char* str);
- void setHeaders();
-
- S32 report(CURLcode);
- void getTransferInfo(LLCurl::TransferInfo* info);
-
- void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false);
-
- const char* getErrorBuffer();
-
- std::stringstream& getInput() { return mInput; }
- std::stringstream& getHeaderOutput() { return mHeaderOutput; }
- LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
- const LLChannelDescriptors& getChannels() { return mChannels; }
-
- void resetState();
-
- static CURL* allocEasyHandle();
- static void releaseEasyHandle(CURL* handle);
-
-private:
- friend class LLCurl;
- friend class LLCurl::Multi;
-
- CURL* mCurlEasyHandle;
- struct curl_slist* mHeaders;
-
- std::stringstream mRequest;
- LLChannelDescriptors mChannels;
- LLIOPipe::buffer_ptr_t mOutput;
- std::stringstream mInput;
- std::stringstream mHeaderOutput;
- char mErrorBuffer[CURL_ERROR_SIZE];
-
- // Note: char*'s not strings since we pass pointers to curl
- std::vector<char*> mStrings;
-
- LLCurl::ResponderPtr mResponder;
-
- static std::set<CURL*> sFreeHandles;
- static std::set<CURL*> sActiveHandles;
- static LLMutex* sHandleMutexp ;
-
- static void deleteAllActiveHandles();
- static void deleteAllFreeHandles();
-};
-
-class LLCurl::Multi
-{
- LOG_CLASS(Multi);
-
- friend class LLCurlThread ;
-
-private:
- ~Multi();
-
- void markDead() ;
- bool doPerform();
-
-public:
-
- typedef enum
- {
- STATE_READY=0,
- STATE_PERFORMING=1,
- STATE_COMPLETED=2
- } ePerformState;
-
- Multi(F32 idle_time_out = 0.f);
-
- LLCurl::Easy* allocEasy();
- bool addEasy(LLCurl::Easy* easy);
- void removeEasy(LLCurl::Easy* easy);
-
- void lock() ;
- void unlock() ;
-
- void setState(ePerformState state) ;
- ePerformState getState() ;
-
- bool isCompleted() ;
- bool isValid() {return mCurlMultiHandle != NULL && mValid;}
- bool isDead() {return mDead;}
-
- bool waitToComplete() ;
-
- S32 process();
-
- CURLMsg* info_read(S32* msgs_in_queue);
-
- S32 mQueued;
- S32 mErrorCount;
-
-private:
- void easyFree(LLCurl::Easy*);
- void cleanup(bool deleted = false) ;
-
- CURLM* mCurlMultiHandle;
-
- typedef std::set<LLCurl::Easy*> easy_active_list_t;
- easy_active_list_t mEasyActiveList;
- typedef std::map<CURL*, LLCurl::Easy*> easy_active_map_t;
- easy_active_map_t mEasyActiveMap;
- typedef std::set<LLCurl::Easy*> easy_free_list_t;
- easy_free_list_t mEasyFreeList;
-
- LLQueuedThread::handle_t mHandle ;
- ePerformState mState;
-
- BOOL mDead ;
- BOOL mValid ;
- LLMutex* mMutexp ;
- LLMutex* mDeletionMutexp ;
- LLMutex* mEasyMutexp ;
- LLFrameTimer mIdleTimer ;
- F32 mIdleTimeOut;
-};
-
-class LLCurlThread : public LLQueuedThread
-{
-public:
-
- class CurlRequest : public LLQueuedThread::QueuedRequest
- {
- protected:
- virtual ~CurlRequest(); // use deleteRequest()
-
- public:
- CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread);
-
- /*virtual*/ bool processRequest();
- /*virtual*/ void finishRequest(bool completed);
-
- private:
- // input
- LLCurl::Multi* mMulti;
- LLCurlThread* mCurlThread;
- };
- friend class CurlRequest;
-
-public:
- LLCurlThread(bool threaded = true) ;
- virtual ~LLCurlThread() ;
-
- S32 update(F32 max_time_ms);
-
- void addMulti(LLCurl::Multi* multi) ;
- void killMulti(LLCurl::Multi* multi) ;
-
-private:
- bool doMultiPerform(LLCurl::Multi* multi) ;
- void deleteMulti(LLCurl::Multi* multi) ;
- void cleanupMulti(LLCurl::Multi* multi) ;
-} ;
-
-
-class LLCurlEasyRequest
-{
-public:
- LLCurlEasyRequest();
- ~LLCurlEasyRequest();
- void setopt(CURLoption option, S32 value);
- void setoptString(CURLoption option, const std::string& value);
- void setPost(char* postdata, S32 size);
- void setHeaderCallback(curl_header_callback callback, void* userdata);
- void setWriteCallback(curl_write_callback callback, void* userdata);
- void setReadCallback(curl_read_callback callback, void* userdata);
- void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
- void slist_append(const std::string& header, const std::string& value);
- void slist_append(const char* str);
- void sendRequest(const std::string& url);
- void requestComplete();
- bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
- std::string getErrorString();
- bool isCompleted() {return mMulti->isCompleted() ;}
- bool wait() { return mMulti->waitToComplete(); }
- bool isValid() {return mMulti && mMulti->isValid(); }
-
- LLCurl::Easy* getEasy() const { return mEasy; }
-
-private:
- CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
-
-private:
- LLCurl::Multi* mMulti;
- LLCurl::Easy* mEasy;
- bool mRequestSent;
- bool mResultReturned;
-};
-
-// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
-namespace LLCurlFF
-{
- void check_easy_code(CURLcode code);
- //void check_multi_code(CURLMcode code);
-}
-
-#endif // LL_LLCURL_H
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index 36a4fc8823..92fcd38d3b 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -26,7 +26,6 @@
#include "llexperiencecache.h"
#include "llavatarname.h"
-#include "llhttpclient.h"
#include "llsdserialize.h"
#include "llcoros.h"
#include "lleventcoro.h"
@@ -84,6 +83,7 @@ const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7;
// default values
const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0;
const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes
+const int LLExperienceCache::SEARCH_PAGE_SIZE = 30;
//=========================================================================
LLExperienceCache::LLExperienceCache():
@@ -248,7 +248,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
//LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -356,7 +356,7 @@ void LLExperienceCache::requestExperiences()
if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD))
{ // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself.
- LLCoprocedureManager::getInstance()->enqueueCoprocedure("ExpCache", "Request",
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "RequestExperiences",
boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) );
ostr.str(std::string());
@@ -401,7 +401,7 @@ void LLExperienceCache::idleCoro()
do
{
timeout.eventAfter(SECS_BETWEEN_REQUESTS, LLSD());
- llcoro::waitForEventOn(timeout);
+ llcoro::suspendUntilEventOn(timeout);
if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
{
@@ -506,7 +506,8 @@ const LLSD& LLExperienceCache::get(const LLUUID& key)
return empty;
}
-void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::Callback_t slot)
+
+void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot)
{
if(key.isNull())
return;
@@ -533,6 +534,358 @@ void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::Callback_t slo
}
//=========================================================================
+void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Fetch Associated",
+ boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, objectId, itemId, fn));
+}
+
+void LLExperienceCache::fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID objectId, LLUUID itemId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ std::string url = mCapability("GetMetadata");
+
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL;
+ return;
+ }
+
+ LLSD fields;
+ fields.append("experience");
+ LLSD data;
+ data["object-id"] = objectId;
+ data["item-id"] = itemId;
+ data["fields"] = fields;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, data);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if ((!status) || (!result.has("experience")))
+ {
+ LLSD failure;
+ if (!status)
+ {
+ failure["error"] = (LLSD::Integer)status.getType();
+ failure["message"] = status.getMessage();
+ }
+ else
+ {
+ failure["error"] = -1;
+ failure["message"] = "no experience";
+ }
+ if (fn && !fn.empty())
+ fn(failure);
+ return;
+ }
+
+ LLUUID expId = result["experience"].asUUID();
+ get(expId, fn);
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Search Name",
+ boost::bind(&LLExperienceCache::findExperienceByNameCoro, this, _1, text, page, fn));
+}
+
+void LLExperienceCache::findExperienceByNameCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string text, int page, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ std::ostringstream url;
+
+
+ url << mCapability("FindExperienceByName") << "?page=" << page << "&page_size=" << SEARCH_PAGE_SIZE << "&query=" << LLURI::escape(text);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url.str());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ fn(LLSD());
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+
+ const LLSD& experiences = result["experience_keys"];
+ for (LLSD::array_const_iterator it = experiences.beginArray(); it != experiences.endArray(); ++it)
+ {
+ insert(*it);
+ }
+
+ fn(result);
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Group Experiences",
+ boost::bind(&LLExperienceCache::getGroupExperiencesCoro, this, _1, groupId, fn));
+}
+
+void LLExperienceCache::getGroupExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID groupId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ // search for experiences owned by the current group
+ std::string url = mCapability("GroupExperiences");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Group Experiences capability" << LL_ENDL;
+ return;
+ }
+
+ url += "?" + groupId.asString();
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ fn(LLSD());
+ return;
+ }
+
+ const LLSD& experienceIds = result["experience_ids"];
+ fn(experienceIds);
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn)
+{
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Region Experiences",
+ boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, regioncaps, false, LLSD(), fn));
+}
+
+void LLExperienceCache::setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn)
+{
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Region Experiences",
+ boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, regioncaps, true, experiences, fn));
+}
+
+void LLExperienceCache::regionExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter,
+ CapabilityQuery_t regioncaps, bool update, LLSD experiences, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ // search for experiences owned by the current group
+ std::string url = regioncaps("RegionExperiences");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
+
+ LLSD result;
+ if (update)
+ result = httpAdapter->postAndSuspend(httpRequest, url, experiences);
+ else
+ result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+// fn(LLSD());
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ fn(result);
+
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
+
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
+
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
+
+void LLExperienceCache::setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string url = mCapability("ExperiencePreferences");
+ if (url.empty())
+ return;
+ LLSD permData;
+ LLSD data;
+ permData["permission"] = permission;
+ data[experienceId.asString()] = permData;
+
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndSuspend), _1, _2, _3, data, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
+
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
+
+void LLExperienceCache::forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
+
+
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
+
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
+
+void LLExperienceCache::experiencePermissionCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, permissionInvoker_fn invokerfn, std::string url, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ // search for experiences owned by the current group
+
+ LLSD result = invokerfn(httpAdapter, httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+
+ if (status)
+ {
+ fn(result);
+ }
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "IsAdmin",
+ boost::bind(&LLExperienceCache::getExperienceAdminCoro, this, _1, experienceId, fn));
+}
+
+void LLExperienceCache::getExperienceAdminCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID experienceId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ std::string url = mCapability("IsExperienceAdmin");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
+ url += "?experience_id=" + experienceId.asString();
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+// LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+// LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ fn(result);
+}
+
+//-------------------------------------------------------------------------
+void LLExperienceCache::updateExperience(LLSD updateData, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "IsAdmin",
+ boost::bind(&LLExperienceCache::updateExperienceCoro, this, _1, updateData, fn));
+}
+
+void LLExperienceCache::updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLSD updateData, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ std::string url = mCapability("UpdateExperience");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
+
+ updateData.erase(LLExperienceCache::QUOTA);
+ updateData.erase(LLExperienceCache::EXPIRES);
+ updateData.erase(LLExperienceCache::AGENT_ID);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, updateData);
+
+ fn(result);
+}
+
+//=========================================================================
void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys)
{
LLSD::array_const_iterator exp = legacyKeys.beginArray();
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index 937225a80a..1002b33f80 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -47,22 +47,39 @@ class LLExperienceCache: public LLSingleton < LLExperienceCache >
public:
typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
- typedef boost::function<void(const LLSD &)> Callback_t;
+ typedef boost::function<void(const LLSD &)> ExperienceGetFn_t;
+ void setCapabilityQuery(CapabilityQuery_t queryfn);
void cleanup();
+ //-------------------------------------------
+ // Cache methods
void erase(const LLUUID& key);
bool fetch(const LLUUID& key, bool refresh = false);
void insert(const LLSD& experience_data);
const LLSD& get(const LLUUID& key);
-
- // If name information is in cache, callback will be called immediately.
- void get(const LLUUID& key, Callback_t slot);
+ void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately.
bool isRequestPending(const LLUUID& public_key);
- void setCapabilityQuery(CapabilityQuery_t queryfn);
+ //-------------------------------------------
+ void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn);
+ void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn);
+ void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn);
+
+ // the Get/Set Region Experiences take a CapabilityQuery to get the capability since
+ // the region being queried may not be the region that the agent is standing on.
+ void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn);
+ void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn);
+
+ void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
+ void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn);
+ void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
+
+ void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn);
+ void updateExperience(LLSD updateData, ExperienceGetFn_t fn);
+ //-------------------------------------------
static const std::string NAME; // "name"
static const std::string EXPERIENCE_ID; // "public_id"
static const std::string AGENT_ID; // "agent_id"
@@ -91,6 +108,7 @@ private:
virtual void initSingleton();
+ typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn;
// Callback types for get()
typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t;
@@ -110,6 +128,7 @@ private:
// default values
static const F64 DEFAULT_EXPIRATION; // 600.0
static const S32 DEFAULT_QUOTA; // 128 this is megabytes
+ static const int SEARCH_PAGE_SIZE;
//--------------------------------------------
void processExperience(const LLUUID& public_key, const LLSD& experience);
@@ -120,7 +139,6 @@ private:
RequestQueue_t mRequestQueue;
PendingQueue_t mPendingQueue;
- LLFrameTimer mRequestTimer;
LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache
CapabilityQuery_t mCapability;
std::string mCacheFileName;
@@ -131,7 +149,13 @@ private:
void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
void requestExperiences();
- void setMaximumLookups(int maximumLookups);
+ void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, ExperienceGetFn_t);
+ void findExperienceByNameCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, int, ExperienceGetFn_t);
+ void getGroupExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID , ExperienceGetFn_t);
+ void regionExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, CapabilityQuery_t regioncaps, bool update, LLSD experiences, ExperienceGetFn_t fn);
+ void experiencePermissionCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, permissionInvoker_fn invokerfn, std::string url, ExperienceGetFn_t fn);
+ void getExperienceAdminCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID experienceId, ExperienceGetFn_t fn);
+ void updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLSD updateData, ExperienceGetFn_t fn);
void bootstrap(const LLSD& legacyKeys, int initialExpiration);
void exportFile(std::ostream& ostr) const;
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
deleted file mode 100755
index e202154445..0000000000
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ /dev/null
@@ -1,1454 +0,0 @@
-/**
- * @file llhttpassetstorage.cpp
- * @brief Subclass capable of loading asset data to/from an external
- * source. Currently, a web server accessed via curl
- *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llhttpassetstorage.h"
-
-#include <sys/stat.h>
-
-#include "indra_constants.h"
-#include "message.h"
-#include "llproxy.h"
-#include "llvfile.h"
-#include "llvfs.h"
-#include "llxfer.h"
-
-#ifdef LL_USESYSTEMLIBS
-# include <zlib.h>
-#else
-# include "zlib/zlib.h"
-#endif
-
-const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset";
-
-const U32 MAX_RUNNING_REQUESTS = 1;
-
-// Try for 30 minutes for now.
-const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;
-
-const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096;
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLTempAssetData
-// An asset not stored on central asset store, but on a simulator node somewhere.
-/////////////////////////////////////////////////////////////////////////////////
-struct LLTempAssetData
-{
- LLUUID mAssetID;
- LLUUID mAgentID;
- std::string mHostName;
-};
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLHTTPAssetRequest
-/////////////////////////////////////////////////////////////////////////////////
-
-class LLHTTPAssetRequest : public LLAssetRequest
-{
-public:
- LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid,
- LLAssetType::EType type, LLAssetStorage::ERequestType rt,
- const std::string& url, CURLM *curl_multi);
- virtual ~LLHTTPAssetRequest();
-
- void setupCurlHandle();
- void cleanupCurlHandle();
-
- void prepareCompressedUpload();
- void finishCompressedUpload();
- size_t readCompressedData(void* data, size_t size);
-
- static size_t curlCompressedUploadCallback(
- void *data, size_t size, size_t nmemb, void *user_data);
-
- virtual LLSD getTerseDetails() const;
- virtual LLSD getFullDetails() const;
-
-public:
- LLHTTPAssetStorage *mAssetStoragep;
-
- CURL *mCurlHandle;
- CURLM *mCurlMultiHandle;
- std::string mURLBuffer;
- struct curl_slist *mHTTPHeaders;
- LLVFile *mVFile;
- LLUUID mTmpUUID;
- LLAssetStorage::ERequestType mRequestType;
-
- bool mZInitialized;
- z_stream mZStream;
- char* mZInputBuffer;
- bool mZInputExhausted;
-
- FILE *mFP;
-};
-
-
-LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp,
- const LLUUID &uuid,
- LLAssetType::EType type,
- LLAssetStorage::ERequestType rt,
- const std::string& url,
- CURLM *curl_multi)
- : LLAssetRequest(uuid, type),
- mZInitialized(false)
-{
- memset(&mZStream, 0, sizeof(mZStream)); // we'll initialize this later, but for now zero the whole C-style struct to avoid debug/coverity noise
- mAssetStoragep = asp;
- mCurlHandle = NULL;
- mCurlMultiHandle = curl_multi;
- mVFile = NULL;
- mRequestType = rt;
- mHTTPHeaders = NULL;
- mFP = NULL;
- mZInputBuffer = NULL;
- mZInputExhausted = false;
-
- mURLBuffer = url;
-}
-
-LLHTTPAssetRequest::~LLHTTPAssetRequest()
-{
- // Cleanup/cancel the request
- if (mCurlHandle)
- {
- curl_multi_remove_handle(mCurlMultiHandle, mCurlHandle);
- cleanupCurlHandle();
- }
- if (mHTTPHeaders)
- {
- curl_slist_free_all(mHTTPHeaders);
- }
- delete mVFile;
- finishCompressedUpload();
-}
-
-// virtual
-LLSD LLHTTPAssetRequest::getTerseDetails() const
-{
- LLSD sd = LLAssetRequest::getTerseDetails();
-
- sd["url"] = mURLBuffer;
-
- return sd;
-}
-
-// virtual
-LLSD LLHTTPAssetRequest::getFullDetails() const
-{
- LLSD sd = LLAssetRequest::getFullDetails();
-
- if (mCurlHandle)
- {
- long curl_response = -1;
- long curl_connect = -1;
- double curl_total_time = -1.0f;
- double curl_size_upload = -1.0f;
- double curl_size_download = -1.0f;
- double curl_content_length_upload = -1.0f;
- double curl_content_length_download = -1.0f;
- long curl_request_size = -1;
- const char* curl_content_type = NULL;
-
- curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CODE, &curl_response);
- curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CONNECTCODE, &curl_connect);
- curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &curl_total_time);
- curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_UPLOAD, &curl_size_upload);
- curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &curl_size_download);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_UPLOAD, &curl_content_length_upload);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curl_content_length_download);
- curl_easy_getinfo(mCurlHandle, CURLINFO_REQUEST_SIZE, &curl_request_size);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_TYPE, &curl_content_type);
-
- sd["curl_response_code"] = (int) curl_response;
- sd["curl_http_connect_code"] = (int) curl_connect;
- sd["curl_total_time"] = curl_total_time;
- sd["curl_size_upload"] = curl_size_upload;
- sd["curl_size_download"] = curl_size_download;
- sd["curl_content_length_upload"] = curl_content_length_upload;
- sd["curl_content_length_download"] = curl_content_length_download;
- sd["curl_request_size"] = (int) curl_request_size;
- if (curl_content_type)
- {
- sd["curl_content_type"] = curl_content_type;
- }
- else
- {
- sd["curl_content_type"] = "";
- }
- }
-
- sd["temp_id"] = mTmpUUID;
- sd["request_type"] = LLAssetStorage::getRequestName(mRequestType);
- sd["z_initialized"] = mZInitialized;
- sd["z_input_exhausted"] = mZInputExhausted;
-
- S32 file_size = -1;
- if (mFP)
- {
- struct stat file_stat;
- int file_desc = fileno(mFP);
- if ( fstat(file_desc, &file_stat) == 0)
- {
- file_size = file_stat.st_size;
- }
- }
- sd["file_size"] = file_size;
-
- return sd;
-}
-
-
-void LLHTTPAssetRequest::setupCurlHandle()
-{
- // *NOTE: Similar code exists in mapserver/llcurlutil.cpp JC
- mCurlHandle = LLCurl::newEasyHandle();
- llassert_always(mCurlHandle != NULL) ;
-
- // Apply proxy settings if configured to do so
- LLProxy::getInstance()->applyProxySettings(mCurlHandle);
-
- curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer.c_str());
- curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
- if (LLAssetStorage::RT_DOWNLOAD == mRequestType)
- {
- curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
- // only do this on downloads, as uploads
- // to some apache configs (like our test grids)
- // mistakenly claim the response is gzip'd if the resource
- // name ends in .gz, even though in a PUT, the response is
- // just plain HTML saying "created"
- }
- /* Remove the Pragma: no-cache header that libcurl inserts by default;
- we want the cached version, if possible. */
- if (mZInitialized)
- {
- curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, "");
- // disable use of proxy, which can't handle chunked transfers
- }
- mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:");
-
- // bug in curl causes DNS to be cached for too long a time, 0 sets it to never cache DNS results internally (to curl)
- curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
-
- // resist the temptation to explicitly add the Transfer-Encoding: chunked
- // header here - invokes a libCURL bug
- curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders);
- if (mAssetStoragep)
- {
- // Set the appropriate pending upload or download flag
- mAssetStoragep->addRunningRequest(mRequestType, this);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetRequest::setupCurlHandle - No asset storage associated with this request!" << LL_ENDL;
- }
-}
-
-void LLHTTPAssetRequest::cleanupCurlHandle()
-{
- LLCurl::deleteEasyHandle(mCurlHandle);
- if (mAssetStoragep)
- {
- // Terminating a request. Thus upload or download is no longer pending.
- mAssetStoragep->removeRunningRequest(mRequestType, this);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetRequest::~LLHTTPAssetRequest - No asset storage associated with this request!" << LL_ENDL;
- }
- mCurlHandle = NULL;
-}
-
-void LLHTTPAssetRequest::prepareCompressedUpload()
-{
- mZStream.next_in = Z_NULL;
- mZStream.avail_in = 0;
- mZStream.zalloc = Z_NULL;
- mZStream.zfree = Z_NULL;
- mZStream.opaque = Z_NULL;
-
- int r = deflateInit2(&mZStream,
- 1, // compression level
- Z_DEFLATED, // the only method defined
- 15 + 16, // the default windowBits + gzip header flag
- 8, // the default memLevel
- Z_DEFAULT_STRATEGY);
-
- if (r != Z_OK)
- {
- LL_ERRS() << "LLHTTPAssetRequest::prepareCompressedUpload defalateInit2() failed" << LL_ENDL;
- }
-
- mZInitialized = true;
- mZInputBuffer = new char[COMPRESSED_INPUT_BUFFER_SIZE];
- mZInputExhausted = false;
-
- mVFile = new LLVFile(gAssetStorage->mVFS,
- getUUID(), getType(), LLVFile::READ);
-}
-
-void LLHTTPAssetRequest::finishCompressedUpload()
-{
- if (mZInitialized)
- {
- LL_INFOS() << "LLHTTPAssetRequest::finishCompressedUpload: "
- << "read " << mZStream.total_in << " byte asset file, "
- << "uploaded " << mZStream.total_out << " byte compressed asset"
- << LL_ENDL;
-
- deflateEnd(&mZStream);
- delete[] mZInputBuffer;
- }
-}
-
-size_t LLHTTPAssetRequest::readCompressedData(void* data, size_t size)
-{
- llassert(mZInitialized);
-
- mZStream.next_out = (Bytef*)data;
- mZStream.avail_out = size;
-
- while (mZStream.avail_out > 0)
- {
- if (mZStream.avail_in == 0 && !mZInputExhausted)
- {
- S32 to_read = llmin(COMPRESSED_INPUT_BUFFER_SIZE,
- (S32)(mVFile->getSize() - mVFile->tell()));
-
- if ( to_read > 0 )
- {
- mVFile->read((U8*)mZInputBuffer, to_read); /*Flawfinder: ignore*/
- mZStream.next_in = (Bytef*)mZInputBuffer;
- mZStream.avail_in = mVFile->getLastBytesRead();
- }
-
- mZInputExhausted = mZStream.avail_in == 0;
- }
-
- int r = deflate(&mZStream,
- mZInputExhausted ? Z_FINISH : Z_NO_FLUSH);
-
- if (r == Z_STREAM_END || r < 0 || mZInputExhausted)
- {
- if (r < 0)
- {
- LL_WARNS() << "LLHTTPAssetRequest::readCompressedData: deflate returned error code "
- << (S32) r << LL_ENDL;
- }
- break;
- }
- }
-
- return size - mZStream.avail_out;
-}
-
-//static
-size_t LLHTTPAssetRequest::curlCompressedUploadCallback(
- void *data, size_t size, size_t nmemb, void *user_data)
-{
- size_t num_read = 0;
-
- if (gAssetStorage)
- {
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
- if (req)
- {
- num_read = req->readCompressedData(data, size * nmemb);
- }
- }
-
- return num_read;
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLHTTPAssetStorage
-/////////////////////////////////////////////////////////////////////////////////
-
-
-LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const LLHost &upstream_host,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host)
-{
- _init(web_host, local_web_host, host_name);
-}
-
-LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs,
- LLVFS *static_vfs,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs, static_vfs)
-{
- _init(web_host, local_web_host, host_name);
-}
-
-void LLHTTPAssetStorage::_init(const std::string& web_host, const std::string& local_web_host, const std::string& host_name)
-{
- mBaseURL = web_host;
- mLocalBaseURL = local_web_host;
- mHostName = host_name;
-
- // curl_global_init moved to LLCurl::initClass()
-
- mCurlMultiHandle = LLCurl::newMultiHandle() ;
- llassert_always(mCurlMultiHandle != NULL) ;
-}
-
-LLHTTPAssetStorage::~LLHTTPAssetStorage()
-{
- LLCurl::deleteMultiHandle(mCurlMultiHandle);
- mCurlMultiHandle = NULL;
-
- // curl_global_cleanup moved to LLCurl::initClass()
-}
-
-// storing data is simpler than getting it, so we just overload the whole method
-void LLHTTPAssetStorage::storeAssetData(
- const LLUUID& uuid,
- LLAssetType::EType type,
- LLAssetStorage::LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool store_local,
- const LLUUID& requesting_agent_id,
- bool user_waiting,
- F64Seconds timeout)
-{
- if (mVFS->getExists(uuid, type)) // VFS treats nonexistant and zero-length identically
- {
- LLAssetRequest *req = new LLAssetRequest(uuid, type);
- req->mUpCallback = callback;
- req->mUserData = user_data;
- req->mRequestingAgentID = requesting_agent_id;
- req->mIsUserWaiting = user_waiting;
- req->mTimeout = timeout;
-
- // LLAssetStorage metric: Successful Request
- S32 size = mVFS->getSize(uuid, type);
- const char *message;
- if( store_local )
- {
- message = "Added to local upload queue";
- }
- else
- {
- message = "Added to upload queue";
- }
- reportMetric( uuid, type, LLStringUtil::null, requesting_agent_id, size, MR_OKAY, __FILE__, __LINE__, message );
-
- // this will get picked up and transmitted in checkForTimeouts
- if(store_local)
- {
- mPendingLocalUploads.push_back(req);
- }
- else if(is_priority)
- {
- mPendingUploads.push_front(req);
- }
- else
- {
- mPendingUploads.push_back(req);
- }
- }
- else
- {
- LL_WARNS() << "AssetStorage: attempt to upload non-existent vfile " << uuid << ":" << LLAssetType::lookup(type) << LL_ENDL;
- if (callback)
- {
- // LLAssetStorage metric: Zero size VFS
- reportMetric( uuid, type, LLStringUtil::null, requesting_agent_id, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
- callback(uuid, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
- }
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::storeAssetData(
- const std::string& filename,
- const LLUUID& asset_id,
- LLAssetType::EType asset_type,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool user_waiting,
- F64Seconds timeout)
-{
- LL_INFOS() << "LLAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
-
- LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
-
- legacy->mUpCallback = callback;
- legacy->mUserData = user_data;
-
- FILE *fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
- S32 size = 0;
- if (fp)
- {
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- }
-
- if( size )
- {
- LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE);
-
- file.setMaxSize(size);
-
- const S32 buf_size = 65536;
- U8 copy_buf[buf_size];
- while ((size = (S32)fread(copy_buf, 1, buf_size, fp)))
- {
- file.write(copy_buf, size);
- }
- fclose(fp);
-
- // if this upload fails, the caller needs to setup a new tempfile for us
- if (temp_file)
- {
- LLFile::remove(filename);
- }
-
- // LLAssetStorage metric: Success not needed; handled in the overloaded method here:
- storeAssetData(
- asset_id,
- asset_type,
- legacyStoreDataCallback,
- (void**)legacy,
- temp_file,
- is_priority,
- false,
- LLUUID::null,
- user_waiting,
- timeout);
- }
- else // !size
- {
- if( fp )
- {
- // LLAssetStorage metric: Zero size
- reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" );
- fclose( fp );
- }
- else
- {
- // LLAssetStorage metric: Missing File
- reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" );
- }
- if (callback)
- {
- callback(LLUUID::null, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
- }
- delete legacy;
- }
-}
-
-// virtual
-LLSD LLHTTPAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const std::string& detail_prefix) const
-{
- LLSD sd = LLAssetStorage::getPendingDetails(rt, asset_type, detail_prefix);
- const request_list_t* running = getRunningList(rt);
- if (running)
- {
- // Loop through the pending requests sd, and add extra info about its running status.
- S32 num_pending = sd["requests"].size();
- S32 i;
- for (i = 0; i < num_pending; ++i)
- {
- LLSD& pending = sd["requests"][i];
- // See if this pending request is running.
- const LLAssetRequest* req = findRequest(running,
- LLAssetType::lookup(pending["type"].asString()),
- pending["asset_id"]);
- if (req)
- {
- // Keep the detail_url so we don't have to rebuild it.
- LLURI detail_url = pending["detail"];
- pending = req->getTerseDetails();
- pending["detail"] = detail_url;
- pending["is_running"] = true;
- }
- else
- {
- pending["is_running"] = false;
- }
- }
- }
- return sd;
-}
-
-// virtual
-LLSD LLHTTPAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id) const
-{
- // Look for this asset in the running list first.
- const request_list_t* running = getRunningList(rt);
- if (running)
- {
- LLSD sd = LLAssetStorage::getPendingRequestImpl(running, asset_type, asset_id);
- if (sd)
- {
- sd["is_running"] = true;
- return sd;
- }
- }
- LLSD sd = LLAssetStorage::getPendingRequest(rt, asset_type, asset_id);
- if (sd)
- {
- sd["is_running"] = false;
- }
- return sd;
-}
-
-// virtual
-bool LLHTTPAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id)
-{
- // Try removing this from the running list first.
- request_list_t* running = getRunningList(rt);
- if (running)
- {
- LLAssetRequest* req = findRequest(running, asset_type, asset_id);
- if (req)
- {
- // Remove this request from the running list to get it out of curl.
- running->remove(req);
-
- // Find this request in the pending list, so we can move it to the end of the line.
- request_list_t* pending = getRequestList(rt);
- if (pending)
- {
- request_list_t::iterator result = std::find_if(pending->begin(), pending->end(),
- std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req));
- if (pending->end() != result)
- {
- // This request was found in the pending list. Move it to the end!
- LLAssetRequest* pending_req = *result;
- pending->remove(pending_req);
-
- if (!pending_req->mIsUserWaiting) //A user is waiting on this request. Toss it.
- {
- pending->push_back(pending_req);
- }
- else
- {
- if (pending_req->mUpCallback) //Clean up here rather than _callUploadCallbacks because this request is already cleared the req.
- {
- pending_req->mUpCallback(pending_req->getUUID(), pending_req->mUserData, -1, LL_EXSTAT_REQUEST_DROPPED);
- }
-
- }
-
- LL_INFOS() << "Asset " << getRequestName(rt) << " request for "
- << asset_id << "." << LLAssetType::lookup(asset_type)
- << " removed from curl and placed at the end of the pending queue."
- << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Unable to find pending " << getRequestName(rt) << " request for "
- << asset_id << "." << LLAssetType::lookup(asset_type) << LL_ENDL;
- }
- }
- delete req;
-
- return true;
- }
- }
- return LLAssetStorage::deletePendingRequest(rt, asset_type, asset_id);
-}
-
-// internal requester, used by getAssetData in superclass
-void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
- void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
- void *user_data, BOOL duplicate,
- BOOL is_priority)
-{
- // stash the callback info so we can find it after we get the response message
- LLAssetRequest *req = new LLAssetRequest(uuid, type);
- req->mDownCallback = callback;
- req->mUserData = user_data;
- req->mIsPriority = is_priority;
-
- // this will get picked up and downloaded in checkForTimeouts
-
- //
- // HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK! Asset requests were taking too long and timing out.
- // Since texture requests are the LEAST sensitive (on the simulator) to being delayed, add
- // non-texture requests to the front, and add texture requests to the back. The theory is
- // that we always want them first, even if they're out of order.
- //
-
- if (req->getType() == LLAssetType::AT_TEXTURE)
- {
- mPendingDownloads.push_back(req);
- }
- else
- {
- mPendingDownloads.push_front(req);
- }
-}
-
-LLAssetRequest* LLHTTPAssetStorage::findNextRequest(LLAssetStorage::request_list_t& pending,
- LLAssetStorage::request_list_t& running)
-{
- // Early exit if the running list is full, or we don't have more pending than running.
- if (running.size() >= MAX_RUNNING_REQUESTS
- || pending.size() <= running.size()) return NULL;
-
- // Look for the first pending request that is not already running.
- request_list_t::iterator running_begin = running.begin();
- request_list_t::iterator running_end = running.end();
-
- request_list_t::iterator pending_iter = pending.begin();
-
- // Loop over all pending requests until we miss finding it in the running list.
- for (; pending_iter != pending.end(); ++pending_iter)
- {
- LLAssetRequest* req = *pending_iter;
- // Look for this pending request in the running list.
- if (running_end == std::find_if(running_begin, running_end,
- std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req)))
- {
- // It isn't running! Return it.
- return req;
- }
- }
- return NULL;
-}
-
-// overloaded to additionally move data to/from the webserver
-void LLHTTPAssetStorage::checkForTimeouts()
-{
- CURLMcode mcode;
- LLAssetRequest *req;
- while ( (req = findNextRequest(mPendingDownloads, mRunningDownloads)) )
- {
- // Setup this curl download request
- // We need to generate a new request here
- // since the one in the list could go away
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
- std::string base_url = getBaseURL(req->getUUID(), req->getType());
- tmp_url = llformat("%s/%36s.%s", base_url.c_str() , uuid_str.c_str(), LLAssetType::lookup(req->getType()));
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle);
- new_req->mTmpUUID.generate();
-
- // Sets pending download flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_DOWNLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- LL_INFOS() << "Requesting " << new_req->mURLBuffer << LL_ENDL;
- }
- }
-
- while ( (req = findNextRequest(mPendingUploads, mRunningUploads)) )
- {
- // setup this curl upload request
-
- bool do_compress = req->getType() == LLAssetType::AT_OBJECT;
-
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
- tmp_url = mBaseURL + "/" + uuid_str + "." + LLAssetType::lookup(req->getType());
- if (do_compress) tmp_url += ".gz";
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle);
-
- if (req->mIsUserWaiting) //If a user is waiting on a realtime response, we want to perserve information across upload attempts.
- {
- new_req->mTime = req->mTime;
- new_req->mTimeout = req->mTimeout;
- new_req->mIsUserWaiting = req->mIsUserWaiting;
- }
-
- if (do_compress)
- {
- new_req->prepareCompressedUpload();
- }
-
- // Sets pending upload flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
-
- if (do_compress)
- {
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
- &LLHTTPAssetRequest::curlCompressedUploadCallback);
- }
- else
- {
- LLVFile file(mVFS, req->getUUID(), req->getType());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
- &curlUpCallback);
- }
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- // Get the uncompressed file size.
- LLVFile file(mVFS,new_req->getUUID(),new_req->getType());
- S32 size = file.getSize();
- LL_INFOS() << "Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << LL_ENDL;
- if (size == 0)
- {
- LL_WARNS() << "Rejecting zero size PUT request!" << LL_ENDL;
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- }
- }
- // Pending upload will have been flagged by the request
- }
-
- while ( (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads)) )
- {
- // setup this curl upload request
- LLVFile file(mVFS, req->getUUID(), req->getType());
-
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
-
- // KLW - All temporary uploads are saved locally "http://localhost:12041/asset"
- tmp_url = llformat("%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str.c_str(), LLAssetType::lookup(req->getType()));
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_LOCALUPLOAD, tmp_url, mCurlMultiHandle);
- new_req->mRequestingAgentID = req->mRequestingAgentID;
-
- // Sets pending upload flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_LOCALUPLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- // Get the uncompressed file size.
- S32 size = file.getSize();
-
- LL_INFOS() << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!"
- << " Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << LL_ENDL;
- if (size == 0)
- {
-
- LL_WARNS() << "Rejecting zero size PUT request!" << LL_ENDL;
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- }
-
- }
- // Pending upload will have been flagged by the request
- }
- S32 count = 0;
- int queue_length;
- do
- {
- mcode = curl_multi_perform(mCurlMultiHandle, &queue_length);
- count++;
- } while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5));
-
- CURLMsg *curl_msg;
- do
- {
- curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
- if (curl_msg && curl_msg->msg == CURLMSG_DONE)
- {
- long curl_result = 0;
- S32 xfer_result = LL_ERR_NOERR;
-
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req);
-
- // TODO: Throw curl_result at all callbacks.
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
- if (RT_UPLOAD == req->mRequestType || RT_LOCALUPLOAD == req->mRequestType)
- {
- if (curl_msg->data.result == CURLE_OK &&
- ( curl_result == HTTP_OK
- || curl_result == HTTP_CREATED
- || curl_result == HTTP_NO_CONTENT))
- {
- LL_INFOS() << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << LL_ENDL;
- if (RT_LOCALUPLOAD == req->mRequestType)
- {
- addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName);
- }
- }
- else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
- curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
- curl_result == HTTP_BAD_GATEWAY ||
- curl_result == HTTP_SERVICE_UNAVAILABLE)
- {
- LL_WARNS() << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
-
- ////HACK (probably) I am sick of this getting requeued and driving me mad.
- //if (req->mIsUserWaiting)
- //{
- // deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
- //}
- }
- else
- {
- LL_WARNS() << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
-
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- }
-
- if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
- curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
- curl_result == HTTP_BAD_GATEWAY ||
- curl_result == HTTP_SERVICE_UNAVAILABLE))
- {
- // shared upload finished callback
- // in the base class, this is called from processUploadComplete
- _callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0), LL_EXSTAT_CURL_RESULT | curl_result);
- // Pending upload flag will get cleared when the request is deleted
- }
- }
- else if (RT_DOWNLOAD == req->mRequestType)
- {
- if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
- {
- if (req->mVFile && req->mVFile->getSize() > 0)
- {
- LL_INFOS() << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << LL_ENDL;
-
- req->mVFile->rename(req->getUUID(), req->getType());
- }
- else
- {
- // *TODO: if this actually indicates a bad asset on the server
- // (not certain at this point), then delete it
- LL_WARNS() << "Found " << req->mURLBuffer << " to be zero size" << LL_ENDL;
- xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
- }
- }
- else
- {
- // KLW - TAT See if an avatar owns this texture, and if so request re-upload.
- LL_WARNS() << "Failure downloading " << req->mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
-
- xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
-
- if (req->mVFile)
- {
- req->mVFile->remove();
- }
- }
-
- // call the static callback for transfer completion
- // this will cleanup all requests for this asset, including ours
- downloadCompleteCallback(
- xfer_result,
- req->getUUID(),
- req->getType(),
- (void *)req,
- LL_EXSTAT_CURL_RESULT | curl_result);
- // Pending download flag will get cleared when the request is deleted
- }
- else
- {
- // nothing, just axe this request
- // currently this can only mean an asset delete
- }
-
- // Deleting clears the pending upload/download flag if it's set and the request is transferring
- delete req;
- req = NULL;
- }
-
- } while (curl_msg && queue_length > 0);
-
-
- // Cleanup
- // We want to bump to the back of the line any running uploads that have timed out.
- bumpTimedOutUploads();
-
- LLAssetStorage::checkForTimeouts();
-}
-
-void LLHTTPAssetStorage::bumpTimedOutUploads()
-{
- bool user_waiting=FALSE;
-
- F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds();
-
- if (mPendingUploads.size())
- {
- request_list_t::iterator it = mPendingUploads.begin();
- LLAssetRequest* req = *it;
- user_waiting=req->mIsUserWaiting;
- }
-
- // No point bumping currently running uploads if there are no others in line.
- if (!(mPendingUploads.size() > mRunningUploads.size()) && !user_waiting)
- {
- return;
- }
-
- // deletePendingRequest will modify the mRunningUploads list so we don't want to iterate over it.
- request_list_t temp_running = mRunningUploads;
-
- request_list_t::iterator it = temp_running.begin();
- request_list_t::iterator end = temp_running.end();
- for ( ; it != end; ++it)
- {
- //request_list_t::iterator curiter = iter++;
- LLAssetRequest* req = *it;
-
- if ( req->mTimeout < (mt_secs - req->mTime) )
- {
- LL_WARNS() << "Asset upload request timed out for "
- << req->getUUID() << "."
- << LLAssetType::lookup(req->getType())
- << ", bumping to the back of the line!" << LL_ENDL;
-
- deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
- }
- }
-}
-
-// static
-size_t LLHTTPAssetStorage::curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Missing gAssetStorage, aborting curl download callback!" << LL_ENDL;
- return 0;
- }
- S32 bytes = (S32)(size * nmemb);
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mVFile)
- {
- req->mVFile = new LLVFile(gAssetStorage->mVFS, req->mTmpUUID, LLAssetType::AT_NONE, LLVFile::APPEND);
- }
-
- double content_length = 0.0;
- curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length);
-
- // sanitize content_length, reconcile w/ actual data
- S32 file_length = llmax(0, (S32)llmin(content_length, 20000000.0), bytes + req->mVFile->getSize());
-
- req->mVFile->setMaxSize(file_length);
- req->mVFile->write((U8*)data, bytes);
-
- return nmemb;
-}
-
-// static
-size_t LLHTTPAssetStorage::curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Missing gAssetStorage, aborting curl download callback!" << LL_ENDL;
- return 0;
- }
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mVFile)
- {
- req->mVFile = new LLVFile(gAssetStorage->mVFS, req->getUUID(), req->getType(), LLVFile::READ);
- }
-
- S32 bytes = llmin((S32)(size * nmemb), (S32)(req->mVFile->getSize() - req->mVFile->tell()));
-
- req->mVFile->read((U8*)data, bytes);/*Flawfinder: ignore*/
-
- return req->mVFile->getLastBytesRead();
-}
-
-// static
-size_t LLHTTPAssetStorage::nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- // do nothing, this is here to soak up script output so it doesn't end up on stdout
-
- return nmemb;
-}
-
-
-
-// blocking asset fetch which bypasses the VFS
-// this is a very limited function for use by the simstate loader and other one-offs
-S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const std::string &url, const std::string& filename, progress_callback callback, void *userdata)
-{
- // *NOTE: There is no guarantee that the uuid and the asset_type match
- // - not that it matters. - Doug
- LL_DEBUGS() << "LLHTTPAssetStorage::getURLToFile() - " << url << LL_ENDL;
-
- FILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
- if (! fp)
- {
- LL_WARNS() << "Failed to open " << filename << " for writing" << LL_ENDL;
- return LL_ERR_ASSET_REQUEST_FAILED;
- }
-
- // make sure we use the normal curl setup, even though we don't really need a request object
- LLHTTPAssetRequest req(this, uuid, asset_type, RT_DOWNLOAD, url, mCurlMultiHandle);
- req.mFP = fp;
-
- req.setupCurlHandle();
- curl_easy_setopt(req.mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEFUNCTION, &curlFileDownCallback);
- curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEDATA, req.mCurlHandle);
-
- curl_multi_add_handle(mCurlMultiHandle, req.mCurlHandle);
- LL_INFOS() << "Requesting as file " << req.mURLBuffer << LL_ENDL;
-
- // braindead curl loop
- int queue_length;
- CURLMsg *curl_msg;
- LLTimer timeout;
- timeout.setTimerExpirySec(GET_URL_TO_FILE_TIMEOUT);
- bool success = false;
- S32 xfer_result = 0;
- do
- {
- curl_multi_perform(mCurlMultiHandle, &queue_length);
- curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
-
- if (callback)
- {
- callback(userdata);
- }
-
- if ( curl_msg && (CURLMSG_DONE == curl_msg->msg) )
- {
- success = true;
- }
- else if (timeout.hasExpired())
- {
- LL_WARNS() << "Request for " << url << " has timed out." << LL_ENDL;
- success = false;
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- break;
- }
- } while (!success);
-
- if (success)
- {
- long curl_result = 0;
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
-
- if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
- {
- S32 size = ftell(req.mFP);
- if (size > 0)
- {
- // everything seems to be in order
- LL_INFOS() << "Success downloading " << req.mURLBuffer << " to file, size " << size << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Found " << req.mURLBuffer << " to be zero size" << LL_ENDL;
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- }
- }
- else
- {
- xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
- LL_INFOS() << "Failure downloading " << req.mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
- }
- }
-
- fclose(fp);
- if (xfer_result)
- {
- LLFile::remove(filename);
- }
- return xfer_result;
-}
-
-
-// static
-size_t LLHTTPAssetStorage::curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mFP)
- {
- LL_WARNS() << "Missing mFP, aborting curl file download callback!" << LL_ENDL;
- return 0;
- }
-
- return fwrite(data, size, nmemb, req->mFP);
-}
-
-LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt)
-{
- switch (rt)
- {
- case RT_DOWNLOAD:
- return &mRunningDownloads;
- case RT_UPLOAD:
- return &mRunningUploads;
- case RT_LOCALUPLOAD:
- return &mRunningLocalUploads;
- default:
- return NULL;
- }
-}
-
-const LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt) const
-{
- switch (rt)
- {
- case RT_DOWNLOAD:
- return &mRunningDownloads;
- case RT_UPLOAD:
- return &mRunningUploads;
- case RT_LOCALUPLOAD:
- return &mRunningLocalUploads;
- default:
- return NULL;
- }
-}
-
-
-void LLHTTPAssetStorage::addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
-{
- request_list_t* requests = getRunningList(rt);
- if (requests)
- {
- requests->push_back(request);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetStorage::addRunningRequest - Request is not an upload OR download, this is bad!" << LL_ENDL;
- }
-}
-
-void LLHTTPAssetStorage::removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
-{
- request_list_t* requests = getRunningList(rt);
- if (requests)
- {
- requests->remove(request);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetStorage::removeRunningRequest - Destroyed request is not an upload OR download, this is bad!" << LL_ENDL;
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
-{
- if (agent_id.isNull() || asset_id.isNull())
- {
- LL_WARNS() << "TAT: addTempAssetData bad id's asset_id: " << asset_id << " agent_id: " << agent_id << LL_ENDL;
- return;
- }
-
- LLTempAssetData temp_asset_data;
- temp_asset_data.mAssetID = asset_id;
- temp_asset_data.mAgentID = agent_id;
- temp_asset_data.mHostName = host_name;
-
- mTempAssets[asset_id] = temp_asset_data;
-}
-
-// virtual
-BOOL LLHTTPAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- BOOL found = (citer != mTempAssets.end());
- return found;
-}
-
-// virtual
-std::string LLHTTPAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- if (citer != mTempAssets.end())
- {
- return citer->second.mHostName;
- }
- else
- {
- return std::string();
- }
-}
-
-// virtual
-LLUUID LLHTTPAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- if (citer != mTempAssets.end())
- {
- return citer->second.mAgentID;
- }
- else
- {
- return LLUUID::null;
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::removeTempAssetData(const LLUUID& asset_id)
-{
- mTempAssets.erase(asset_id);
-}
-
-// virtual
-void LLHTTPAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
-{
- uuid_tempdata_map::iterator it = mTempAssets.begin();
- uuid_tempdata_map::iterator end = mTempAssets.end();
-
- while (it != end)
- {
- const LLTempAssetData& asset_data = it->second;
- if (asset_data.mAgentID == agent_id)
- {
- mTempAssets.erase(it++);
- }
- else
- {
- ++it;
- }
- }
-}
-
-std::string LLHTTPAssetStorage::getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type)
-{
- if (LLAssetType::AT_TEXTURE == asset_type)
- {
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(asset_id);
- if (citer != mTempAssets.end())
- {
- const std::string& host_name = citer->second.mHostName;
- std::string url = llformat(LOCAL_ASSET_URL_FORMAT, host_name.c_str());
- return url;
- }
- }
-
- return mBaseURL;
-}
-
-void LLHTTPAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
-{
- uuid_tempdata_map::const_iterator it = mTempAssets.begin();
- uuid_tempdata_map::const_iterator end = mTempAssets.end();
- S32 count = 0;
- for ( ; it != end; ++it)
- {
- const LLTempAssetData& temp_asset_data = it->second;
- if (avatar_id.isNull()
- || avatar_id == temp_asset_data.mAgentID)
- {
- LL_INFOS() << "TAT: dump agent " << temp_asset_data.mAgentID
- << " texture " << temp_asset_data.mAssetID
- << " host " << temp_asset_data.mHostName
- << LL_ENDL;
- count++;
- }
- }
-
- if (avatar_id.isNull())
- {
- LL_INFOS() << "TAT: dumped " << count << " entries for all avatars" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "TAT: dumped " << count << " entries for avatar " << avatar_id << LL_ENDL;
- }
-}
-
-void LLHTTPAssetStorage::clearTempAssetData()
-{
- LL_INFOS() << "TAT: Clearing temp asset data map" << LL_ENDL;
- mTempAssets.clear();
-}
diff --git a/indra/llmessage/llhttpassetstorage.h b/indra/llmessage/llhttpassetstorage.h
deleted file mode 100755
index 783e95cac6..0000000000
--- a/indra/llmessage/llhttpassetstorage.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @file llhttpassetstorage.h
- * @brief Class for loading asset data to/from an external source over http.
- *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LLHTTPASSETSTORAGE_H
-#define LLHTTPASSETSTORAGE_H
-
-#include "llassetstorage.h"
-#include "curl/curl.h"
-
-class LLVFile;
-class LLHTTPAssetRequest;
-typedef void (*progress_callback)(void* userdata);
-
-struct LLTempAssetData;
-
-typedef std::map<LLUUID,LLTempAssetData> uuid_tempdata_map;
-
-class LLHTTPAssetStorage : public LLAssetStorage
-{
-public:
- LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const LLHost &upstream_host,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name);
-
- LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name);
-
-
- virtual ~LLHTTPAssetStorage();
-
- using LLAssetStorage::storeAssetData; // Unhiding virtuals...
-
- virtual void storeAssetData(
- const LLUUID& uuid,
- LLAssetType::EType atype,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file = false,
- bool is_priority = false,
- bool store_local = false,
- const LLUUID& requesting_agent_id = LLUUID::null,
- bool user_waiting=FALSE,
- F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
-
- virtual void storeAssetData(
- const std::string& filename,
- const LLUUID& asset_id,
- LLAssetType::EType atype,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool user_waiting=FALSE,
- F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
-
- virtual LLSD getPendingDetails(ERequestType rt,
- LLAssetType::EType asset_type,
- const std::string& detail_prefix) const;
-
- virtual LLSD getPendingRequest(ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id) const;
-
- virtual bool deletePendingRequest(ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id);
-
- // Hack. One off curl download an URL to a file. Probably should be elsewhere.
- // Only used by lldynamicstate. The API is broken, and should be replaced with
- // a generic HTTP file fetch - Doug 9/25/06
- S32 getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const std::string &url, const std::string& filename, progress_callback callback, void *userdata);
-
- LLAssetRequest* findNextRequest(request_list_t& pending, request_list_t& running);
-
- void checkForTimeouts();
-
- static size_t curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data);
-
- // Should only be used by the LLHTTPAssetRequest
- void addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
- void removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
-
- request_list_t* getRunningList(ERequestType rt);
- const request_list_t* getRunningList(ERequestType rt) const;
-
- // Temp assets are stored on sim nodes, they have agent ID and location data associated with them.
- virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name);
- virtual BOOL hasTempAssetData(const LLUUID& texture_id) const;
- virtual std::string getTempAssetHostName(const LLUUID& texture_id) const;
- virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const;
- virtual void removeTempAssetData(const LLUUID& asset_id);
- virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id);
-
- // Pass LLUUID::null for all
- virtual void dumpTempAssetData(const LLUUID& avatar_id) const;
- virtual void clearTempAssetData();
-
-protected:
- void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
- void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
- void *user_data, BOOL duplicate, BOOL is_priority);
-
-private:
- void _init(const std::string& web_host, const std::string& local_web_host, const std::string& host_name);
-
- // This will return the correct base URI for any http asset request
- std::string getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type);
-
- // Check for running uploads that have timed out
- // Bump these to the back of the line to let other uploads complete.
- void bumpTimedOutUploads();
-
-protected:
- std::string mBaseURL;
- std::string mLocalBaseURL;
- std::string mHostName;
-
- CURLM *mCurlMultiHandle;
-
- request_list_t mRunningDownloads;
- request_list_t mRunningUploads;
- request_list_t mRunningLocalUploads;
-
- uuid_tempdata_map mTempAssets;
-};
-
-#endif
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
deleted file mode 100755
index b149d24c4b..0000000000
--- a/indra/llmessage/llhttpclient.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/**
- * @file llhttpclient.cpp
- * @brief Implementation of classes for making HTTP requests.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include <openssl/x509_vfy.h>
-#include "llhttpclient.h"
-
-#include "llassetstorage.h"
-#include "lliopipe.h"
-#include "llurlrequest.h"
-#include "llbufferstream.h"
-#include "llsdserialize.h"
-#include "llvfile.h"
-#include "llvfs.h"
-#include "lluri.h"
-
-#include "message.h"
-#include "httpcommon.h"
-#include "httprequest.h"
-#include "httpoptions.h"
-
-#include <curl/curl.h>
-
-
-const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
-LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
-
-////////////////////////////////////////////////////////////////////////////
-
-// Responder class moved to LLCurl
-
-namespace
-{
- class LLHTTPClientURLAdaptor : public LLURLRequestComplete
- {
- public:
- LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder)
- : LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR),
- mReason("LLURLRequest complete w/no status")
- {
- }
-
- ~LLHTTPClientURLAdaptor()
- {
- }
-
- virtual void httpStatus(S32 status, const std::string& reason)
- {
- LLURLRequestComplete::httpStatus(status,reason);
-
- mStatus = status;
- mReason = reason;
- }
-
- virtual void complete(const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer)
- {
- // *TODO: Re-interpret mRequestStatus codes?
- // Would like to detect curl errors, such as
- // connection errors, write erros, etc.
- if (mResponder.get())
- {
- mResponder->setResult(mStatus, mReason);
- mResponder->completedRaw(channels, buffer);
- }
- }
- virtual void header(const std::string& header, const std::string& value)
- {
- if (mResponder.get())
- {
- mResponder->setResponseHeader(header, value);
- }
- }
-
- private:
- LLCurl::ResponderPtr mResponder;
- S32 mStatus;
- std::string mReason;
- };
-
- class Injector : public LLIOPipe
- {
- public:
- virtual const std::string& contentType() = 0;
- };
-
- class LLSDInjector : public Injector
- {
- public:
- LLSDInjector(const LLSD& sd) : mSD(sd) {}
- virtual ~LLSDInjector() {}
-
- const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; }
-
- virtual EStatus process_impl(const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
- {
- LLBufferStream ostream(channels, buffer.get());
- LLSDSerialize::toXML(mSD, ostream);
- eos = true;
- return STATUS_DONE;
- }
-
- const LLSD mSD;
- };
-
- class RawInjector : public Injector
- {
- public:
- RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
- virtual ~RawInjector() {delete [] mData;}
-
- const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
-
- virtual EStatus process_impl(const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
- {
- LLBufferStream ostream(channels, buffer.get());
- ostream.write((const char *)mData, mSize); // hopefully chars are always U8s
- eos = true;
- return STATUS_DONE;
- }
-
- const U8* mData;
- S32 mSize;
- };
-
- class FileInjector : public Injector
- {
- public:
- FileInjector(const std::string& filename) : mFilename(filename) {}
- virtual ~FileInjector() {}
-
- const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
-
- virtual EStatus process_impl(const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
- {
- LLBufferStream ostream(channels, buffer.get());
-
- llifstream fstream(mFilename.c_str(), std::iostream::binary | std::iostream::out);
- if(fstream.is_open())
- {
- fstream.seekg(0, std::ios::end);
- U32 fileSize = (U32)fstream.tellg();
- fstream.seekg(0, std::ios::beg);
- std::vector<char> fileBuffer(fileSize);
- fstream.read(&fileBuffer[0], fileSize);
- ostream.write(&fileBuffer[0], fileSize);
- fstream.close();
- eos = true;
- return STATUS_DONE;
- }
-
- return STATUS_ERROR;
- }
-
- const std::string mFilename;
- };
-
- class VFileInjector : public Injector
- {
- public:
- VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {}
- virtual ~VFileInjector() {}
-
- const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
-
- virtual EStatus process_impl(const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
- {
- LLBufferStream ostream(channels, buffer.get());
-
- LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
- S32 fileSize = vfile.getSize();
- U8* fileBuffer;
- fileBuffer = new U8 [fileSize];
- vfile.read(fileBuffer, fileSize);
- ostream.write((char*)fileBuffer, fileSize);
- delete [] fileBuffer;
- eos = true;
- return STATUS_DONE;
- }
-
- const LLUUID mUUID;
- LLAssetType::EType mAssetType;
- };
-
-
- LLPumpIO* theClientPump = NULL;
-}
-
-void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
-{
- LLHTTPClient::mCertVerifyCallback = callback;
-}
-
-static void request(
- const std::string& url,
- EHTTPMethod method,
- Injector* body_injector,
- LLCurl::ResponderPtr responder,
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
- const LLSD& headers = LLSD(),
- bool follow_redirects = true
- )
-{
- if (!LLHTTPClient::hasPump())
- {
- if (responder)
- {
- responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
- }
- delete body_injector;
- return;
- }
- LLPumpIO::chain_t chain;
-
- LLURLRequest* req = new LLURLRequest(method, url, follow_redirects);
- if(!req->isValid())//failed
- {
- if (responder)
- {
- responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure");
- }
- delete req;
- delete body_injector;
- return;
- }
-
- req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
-
- LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;
-
- // Insert custom headers if the caller sent any
- if (headers.isMap())
- {
- if (headers.has(HTTP_OUT_HEADER_COOKIE))
- {
- req->allowCookies();
- }
-
- LLSD::map_const_iterator iter = headers.beginMap();
- LLSD::map_const_iterator end = headers.endMap();
-
- for (; iter != end; ++iter)
- {
- //if the header is "Pragma" with no value
- //the caller intends to force libcurl to drop
- //the Pragma header it so gratuitously inserts
- //Before inserting the header, force libcurl
- //to not use the proxy (read: llurlrequest.cpp)
- if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty()))
- {
- req->useProxy(false);
- }
- LL_DEBUGS("LLHTTPClient") << "header = " << iter->first
- << ": " << iter->second.asString() << LL_ENDL;
- req->addHeader(iter->first, iter->second.asString());
- }
- }
-
- // Check to see if we have already set Accept or not. If no one
- // set it, set it to application/llsd+xml since that's what we
- // almost always want.
- if( method != HTTP_PUT && method != HTTP_POST )
- {
- if(!headers.has(HTTP_OUT_HEADER_ACCEPT))
- {
- req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
- }
- }
-
- if (responder)
- {
- responder->setURL(url);
- responder->setHTTPMethod(method);
- }
-
- req->setCallback(new LLHTTPClientURLAdaptor(responder));
-
- if (method == HTTP_POST && gMessageSystem)
- {
- req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d",
- gMessageSystem->mPort));
- }
-
- if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
- {
- if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))
- {
- // If the Content-Type header was passed in, it has
- // already been added as a header through req->addHeader
- // in the loop above. We defer to the caller's wisdom, but
- // if they did not specify a Content-Type, then ask the
- // injector.
- req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());
- }
- chain.push_back(LLIOPipe::ptr_t(body_injector));
- }
-
- chain.push_back(LLIOPipe::ptr_t(req));
-
- theClientPump->addChain(chain, timeout);
-}
-
-
-void LLHTTPClient::getByteRange(
- const std::string& url,
- S32 offset,
- S32 bytes,
- ResponderPtr responder,
- const LLSD& hdrs,
- const F32 timeout,
- bool follow_redirects /* = true */)
-{
- LLSD headers = hdrs;
- if(offset > 0 || bytes > 0)
- {
- std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
- headers[HTTP_OUT_HEADER_RANGE] = range;
- }
- request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
-}
-
-void LLHTTPClient::head(
- const std::string& url,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout,
- bool follow_redirects /* = true */)
-{
- request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
-}
-
-void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout,
- bool follow_redirects /* = true */)
-{
- request(url, HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
-}
-void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers,
- const F32 timeout, bool follow_redirects /* = true */)
-{
- request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
-}
-void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,
- bool follow_redirects /* = true */)
-{
- getHeaderOnly(url, responder, LLSD(), timeout, follow_redirects);
-}
-
-void LLHTTPClient::get(const std::string& url, const LLSD& query, ResponderPtr responder, const LLSD& headers,
- const F32 timeout, bool follow_redirects /* = true */)
-{
- LLURI uri;
-
- uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
- get(uri.asString(), responder, headers, timeout, follow_redirects);
-}
-
-// A simple class for managing data returned from a curl http request.
-class LLHTTPBuffer
-{
-public:
- LLHTTPBuffer() { }
-
- static size_t curl_write( void *ptr, size_t size, size_t nmemb, void *user_data)
- {
- LLHTTPBuffer* self = (LLHTTPBuffer*)user_data;
-
- size_t bytes = (size * nmemb);
- self->mBuffer.append((char*)ptr,bytes);
- return nmemb;
- }
-
- LLSD asLLSD()
- {
- LLSD content;
-
- if (mBuffer.empty()) return content;
-
- std::istringstream istr(mBuffer);
- LLSDSerialize::fromXML(content, istr);
- return content;
- }
-
- const std::string& asString()
- {
- return mBuffer;
- }
-
-private:
- std::string mBuffer;
-};
-
-// These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome.
-
-/**
- @brief does a blocking request on the url, returning the data or bad status.
-
- @param url URI to verb on.
- @param method the verb to hit the URI with.
- @param body the body of the call (if needed - for instance not used for GET and DELETE, but is for POST and PUT)
- @param headers HTTP headers to use for the request.
- @param timeout Curl timeout to use. Defaults to 5. Rationale:
- Without this timeout, blockingGet() calls have been observed to take
- up to 90 seconds to complete. Users of blockingGet() already must
- check the HTTP return code for validity, so this will not introduce
- new errors. A 5 second timeout will succeed > 95% of the time (and
- probably > 99% of the time) based on my statistics. JC
-
- @returns an LLSD map: {status: integer, body: map}
- */
-static LLSD blocking_request(
- const std::string& url,
- EHTTPMethod method,
- const LLSD& body,
- const LLSD& headers = LLSD(),
- const F32 timeout = 5
-)
-{
- LL_DEBUGS() << "blockingRequest of " << url << LL_ENDL;
- char curl_error_buffer[CURL_ERROR_SIZE] = "\0";
- CURL* curlp = LLCurl::newEasyHandle();
- llassert_always(curlp != NULL) ;
-
- LLHTTPBuffer http_buffer;
- std::string body_str;
-
- // other request method checks root cert first, we skip?
-
- // Apply configured proxy settings
- LLProxy::getInstance()->applyProxySettings(curlp);
-
- // * Set curl handle options
- curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
- curl_easy_setopt(curlp, CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
- curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, LLHTTPBuffer::curl_write);
- curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);
- curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
- curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer);
-
- // * Setup headers (don't forget to free them after the call!)
- curl_slist* headers_list = NULL;
- if (headers.isMap())
- {
- LLSD::map_const_iterator iter = headers.beginMap();
- LLSD::map_const_iterator end = headers.endMap();
- for (; iter != end; ++iter)
- {
- std::ostringstream header;
- header << iter->first << ": " << iter->second.asString() ;
- LL_DEBUGS() << "header = " << header.str() << LL_ENDL;
- headers_list = curl_slist_append(headers_list, header.str().c_str());
- }
- }
-
- // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
- if (method == HTTP_GET)
- {
- curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
- }
- else if (method == HTTP_POST)
- {
- curl_easy_setopt(curlp, CURLOPT_POST, 1);
- //serialize to ostr then copy to str - need to because ostr ptr is unstable :(
- std::ostringstream ostr;
- LLSDSerialize::toXML(body, ostr);
- body_str = ostr.str();
- curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
- //copied from PHP libs, correct?
- headers_list = curl_slist_append(headers_list,
- llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
-
- // copied from llurlrequest.cpp
- // it appears that apache2.2.3 or django in etch is busted. If
- // we do not clear the expect header, we get a 500. May be
- // limited to django/mod_wsgi.
- headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());
- }
-
- // * Do the action using curl, handle results
- LL_DEBUGS() << "HTTP body: " << body_str << LL_ENDL;
- headers_list = curl_slist_append(headers_list,
- llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
- CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
- if ( curl_result != CURLE_OK )
- {
- LL_INFOS() << "Curl is hosed - can't add headers" << LL_ENDL;
- }
-
- LLSD response = LLSD::emptyMap();
- S32 curl_success = curl_easy_perform(curlp);
- S32 http_status = HTTP_INTERNAL_ERROR;
- curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
- response["status"] = http_status;
- // if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
- if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )
- {
- // We expect 404s, don't spam for them.
- LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL;
- LL_WARNS() << "CURL REQ METHOD TYPE: " << method << LL_ENDL;
- LL_WARNS() << "CURL REQ HEADERS: " << headers.asString() << LL_ENDL;
- LL_WARNS() << "CURL REQ BODY: " << body_str << LL_ENDL;
- LL_WARNS() << "CURL HTTP_STATUS: " << http_status << LL_ENDL;
- LL_WARNS() << "CURL ERROR: " << curl_error_buffer << LL_ENDL;
- LL_WARNS() << "CURL ERROR BODY: " << http_buffer.asString() << LL_ENDL;
- response["body"] = http_buffer.asString();
- }
- else
- {
- response["body"] = http_buffer.asLLSD();
- LL_DEBUGS() << "CURL response: " << http_buffer.asString() << LL_ENDL;
- }
-
- if(headers_list)
- { // free the header list
- curl_slist_free_all(headers_list);
- }
-
- // * Cleanup
- LLCurl::deleteEasyHandle(curlp);
- return response;
-}
-
-LLSD LLHTTPClient::blockingGet(const std::string& url)
-{
- return blocking_request(url, HTTP_GET, LLSD());
-}
-
-LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
-{
- return blocking_request(url, HTTP_POST, body);
-}
-
-void LLHTTPClient::put(
- const std::string& url,
- const LLSD& body,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
-}
-
-void LLHTTPClient::patch(
- const std::string& url,
- const LLSD& body,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);
-}
-
-void LLHTTPClient::putRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_PUT, new RawInjector(data, size), responder, timeout, headers);
-}
-
-void LLHTTPClient::post(
- const std::string& url,
- const LLSD& body,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
-}
-
-void LLHTTPClient::postRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
-}
-
-void LLHTTPClient::postFile(
- const std::string& url,
- const std::string& filename,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);
-}
-
-void LLHTTPClient::postFile(
- const std::string& url,
- const LLUUID& uuid,
- LLAssetType::EType asset_type,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
-}
-
-// static
-void LLHTTPClient::del(
- const std::string& url,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_DELETE, NULL, responder, timeout, headers);
-}
-
-// static
-void LLHTTPClient::move(
- const std::string& url,
- const std::string& destination,
- ResponderPtr responder,
- const LLSD& hdrs,
- const F32 timeout)
-{
- LLSD headers = hdrs;
- headers[HTTP_OUT_HEADER_DESTINATION] = destination;
- request(url, HTTP_MOVE, NULL, responder, timeout, headers);
-}
-
-// static
-void LLHTTPClient::copy(
- const std::string& url,
- const std::string& destination,
- ResponderPtr responder,
- const LLSD& hdrs,
- const F32 timeout)
-{
- LLSD headers = hdrs;
- headers[HTTP_OUT_HEADER_DESTINATION] = destination;
- request(url, HTTP_COPY, NULL, responder, timeout, headers);
-}
-
-
-void LLHTTPClient::setPump(LLPumpIO& pump)
-{
- theClientPump = &pump;
-}
-
-bool LLHTTPClient::hasPump()
-{
- return theClientPump != NULL;
-}
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
deleted file mode 100755
index fd48b4a743..0000000000
--- a/indra/llmessage/llhttpclient.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * @file llhttpclient.h
- * @brief Declaration of classes for making HTTP client requests.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLHTTPCLIENT_H
-#define LL_LLHTTPCLIENT_H
-
-/**
- * These classes represent the HTTP client framework.
- */
-
-#include <string>
-
-#include <boost/intrusive_ptr.hpp>
-#include <openssl/x509_vfy.h>
-#include "llurlrequest.h"
-#include "llassettype.h"
-#include "llcurl.h"
-#include "lliopipe.h"
-
-extern const F32 HTTP_REQUEST_EXPIRY_SECS;
-
-class LLUUID;
-class LLPumpIO;
-class LLSD;
-
-
-class LLHTTPClient
-{
-public:
- // class Responder moved to LLCurl
-
- // For convenience
- typedef LLCurl::Responder Responder;
- typedef LLCurl::ResponderPtr ResponderPtr;
-
-
- /** @name non-blocking API */
- //@{
- static void head(
- const std::string& url,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
- bool follow_redirects = true);
- static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr,
- const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
- bool follow_redirects = true);
- static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
- static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
-
- static void put(
- const std::string& url,
- const LLSD& body,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void putRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
-
- static void patch(
- const std::string& url,
- const LLSD& body,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
- static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
- bool follow_redirects = true);
- static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers,
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
-
- static void post(
- const std::string& url,
- const LLSD& body,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- /** Takes ownership of data and deletes it when sent */
- static void postRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void postFile(
- const std::string& url,
- const std::string& filename,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void postFile(
- const std::string& url,
- const LLUUID& uuid,
- LLAssetType::EType asset_type,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
- static void del(
- const std::string& url,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- ///< sends a DELETE method, but we can't call it delete in c++
-
- /**
- * @brief Send a MOVE webdav method
- *
- * @param url The complete serialized (and escaped) url to get.
- * @param destination The complete serialized destination url.
- * @param responder The responder that will handle the result.
- * @param headers A map of key:value headers to pass to the request
- * @param timeout The number of seconds to give the server to respond.
- */
- static void move(
- const std::string& url,
- const std::string& destination,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
- /**
- * @brief Send a COPY webdav method
- *
- * @param url The complete serialized (and escaped) url to get.
- * @param destination The complete serialized destination url.
- * @param responder The responder that will handle the result.
- * @param headers A map of key:value headers to pass to the request
- * @param timeout The number of seconds to give the server to respond.
- */
- static void copy(
- const std::string& url,
- const std::string& destination,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
- //@}
-
- /**
- * @brief Blocking HTTP get that returns an LLSD map of status and body.
- *
- * @param url the complete serialized (and escaped) url to get
- * @return An LLSD of { 'status':status, 'body':payload }
- */
- static LLSD blockingGet(const std::string& url);
-
- /**
- * @brief Blocking HTTP POST that returns an LLSD map of status and body.
- *
- * @param url the complete serialized (and escaped) url to get
- * @param body the LLSD post body
- * @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) }
- */
- static LLSD blockingPost(const std::string& url, const LLSD& body);
-
-
- static void setPump(LLPumpIO& pump);
- ///< must be called before any of the above calls are made
- static bool hasPump();
-
- static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
- static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
-
-protected:
- static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
-};
-
-#endif // LL_LLHTTPCLIENT_H
diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h
deleted file mode 100755
index 9c1c8e7c11..0000000000
--- a/indra/llmessage/llhttpclientinterface.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file llhttpclientinterface.h
- * @brief
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLHTTPCLIENTINTERFACE_H
-#define LL_LLHTTPCLIENTINTERFACE_H
-
-#include "linden_common.h"
-#include "llcurl.h"
-
-#include <string>
-
-// class LLHTTPClientInterface
-// {
-// public:
-// virtual ~LLHTTPClientInterface() {}
-// virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
-// virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
-// virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
-// };
-
-#endif // LL_LLHTTPCLIENTINTERFACE_H
-
diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp
index d99bdd3f66..648bc5cfd8 100644
--- a/indra/llmessage/llhttpsdhandler.cpp
+++ b/indra/llmessage/llhttpsdhandler.cpp
@@ -36,8 +36,7 @@
#include "llcorehttputil.h"
//========================================================================
-LLHttpSDHandler::LLHttpSDHandler(bool selfDelete):
- mSelfDelete(selfDelete)
+LLHttpSDHandler::LLHttpSDHandler()
{
}
@@ -75,31 +74,4 @@ void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
this->onSuccess(response, resplsd);
}
- // The handler must destroy itself when it is done.
- // *TODO: I'm not fond of this pattern. A class shooting itself in the head
- // outside of a smart pointer always makes me nervous.
- if (mSelfDelete)
- delete this;
-}
-
-//========================================================================
-LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &name, bool selfDelete):
- LLHttpSDHandler(selfDelete),
- mName(name)
-{
-}
-
-void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
-{
- LL_DEBUGS() << mName << " Success." << LL_ENDL;
-}
-
-void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
-{
- LL_WARNS()
- << "\n--------------------------------------------------------------------------\n"
- << mName << " Error[" << status.toULong() << "] cannot access cap with url '"
- << response->getRequestURL() << "' because " << status.toString()
- << "\n--------------------------------------------------------------------------"
- << LL_ENDL;
}
diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h
index 3b81dc66b9..ce40bdfc08 100644
--- a/indra/llmessage/llhttpsdhandler.h
+++ b/indra/llmessage/llhttpsdhandler.h
@@ -44,29 +44,12 @@ public:
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
protected:
- LLHttpSDHandler(bool selfDelete = true);
+ LLHttpSDHandler();
virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0;
virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0;
-private:
- bool mSelfDelete;
};
-/// A trivial implementation of LLHttpSDHandler. This success and failure
-/// methods log the action taken, the URI accessed and the status code returned
-/// in the response.
-class LLHttpSDGenericHandler : public LLHttpSDHandler
-{
-public:
- LLHttpSDGenericHandler(const std::string &name, bool selfDelete = true);
-
-protected:
- virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
- virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
-
-private:
- std::string mName;
-};
#endif
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index 9b8d19cc3e..537efa69d8 100755
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -30,9 +30,8 @@
#include <string>
#include <curl/curl.h>
-
+#include "httpcommon.h"
#include "llapr.h"
-#include "llcurl.h"
#include "llhost.h"
// Static class variable instances
@@ -408,16 +407,6 @@ void LLProxy::cleanupClass()
deleteSingleton();
}
-void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
-{
- applyProxySettings(handle->getEasy());
-}
-
-void LLProxy::applyProxySettings(LLCurl::Easy* handle)
-{
- applyProxySettings(handle->getCurlHandle());
-}
-
/**
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
*
@@ -439,21 +428,21 @@ void LLProxy::applyProxySettings(CURL* handle)
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (mHTTPProxyEnabled)
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY);
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()), CURLOPT_PROXYPORT);
if (mProxyType == LLPROXY_SOCKS)
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE);
if (mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD);
}
}
else
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE);
}
}
}
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
index a919370540..bd23dd39de 100755
--- a/indra/llmessage/llproxy.h
+++ b/indra/llmessage/llproxy.h
@@ -27,12 +27,12 @@
#ifndef LL_PROXY_H
#define LL_PROXY_H
-#include "llcurl.h"
#include "llhost.h"
#include "lliosocket.h"
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
+#include <curl/curl.h>
#include <string>
// SOCKS error codes returned from the StartProxy method
@@ -208,16 +208,13 @@ enum LLSocks5AuthType
* thread-safe method to apply those options to a curl request
* (LLProxy::applyProxySettings()). This method is overloaded
* to accommodate the various abstraction libcurl layers that exist
- * throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
- *
- * If you are working with LLCurl or LLCurlEasyRequest objects,
- * the configured proxy settings will be applied in the constructors
- * of those request handles. If you are working with CURL objects
- * directly, you will need to pass the handle of the request to
- * applyProxySettings() before issuing the request.
+ * throughout the viewer (CURL).
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
+ *
+ * *TODO$: This should be moved into the LLCore::Http space.
+ *
*/
class LLProxy: public LLSingleton<LLProxy>
{
@@ -252,9 +249,6 @@ public:
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
void applyProxySettings(CURL* handle);
- void applyProxySettings(LLCurl::Easy* handle);
- void applyProxySettings(LLCurlEasyRequest* handle);
-
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
diff --git a/indra/llmessage/llsdrpcclient.cpp b/indra/llmessage/llsdrpcclient.cpp
deleted file mode 100755
index eb773ceb3a..0000000000
--- a/indra/llmessage/llsdrpcclient.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/**
- * @file llsdrpcclient.cpp
- * @author Phoenix
- * @date 2005-11-05
- * @brief Implementation of the llsd client classes.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llsdrpcclient.h"
-
-#include "llbufferstream.h"
-#include "llfasttimer.h"
-#include "llfiltersd2xmlrpc.h"
-#include "llpumpio.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "llurlrequest.h"
-
-/**
- * String constants
- */
-static std::string LLSDRPC_RESPONSE_NAME("response");
-static std::string LLSDRPC_FAULT_NAME("fault");
-
-/**
- * LLSDRPCResponse
- */
-LLSDRPCResponse::LLSDRPCResponse() :
- mIsError(false),
- mIsFault(false)
-{
-}
-
-// virtual
-LLSDRPCResponse::~LLSDRPCResponse()
-{
-}
-
-bool LLSDRPCResponse::extractResponse(const LLSD& sd)
-{
- bool rv = true;
- if(sd.has(LLSDRPC_RESPONSE_NAME))
- {
- mReturnValue = sd[LLSDRPC_RESPONSE_NAME];
- mIsFault = false;
- }
- else if(sd.has(LLSDRPC_FAULT_NAME))
- {
- mReturnValue = sd[LLSDRPC_FAULT_NAME];
- mIsFault = true;
- }
- else
- {
- mReturnValue.clear();
- mIsError = true;
- rv = false;
- }
- return rv;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_SDRPC_RESPONSE("SDRPC Response");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCResponse::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_SDRPC_RESPONSE);
- PUMP_DEBUG;
- if(mIsError)
- {
- error(pump);
- }
- else if(mIsFault)
- {
- fault(pump);
- }
- else
- {
- response(pump);
- }
- PUMP_DEBUG;
- return STATUS_DONE;
-}
-
-/**
- * LLSDRPCClient
- */
-
-LLSDRPCClient::LLSDRPCClient() :
- mState(STATE_NONE),
- mQueue(EPBQ_PROCESS)
-{
-}
-
-// virtual
-LLSDRPCClient::~LLSDRPCClient()
-{
-}
-
-bool LLSDRPCClient::call(
- const std::string& uri,
- const std::string& method,
- const LLSD& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue)
-{
- //LL_INFOS() << "RPC: " << uri << "." << method << "(" << *parameter << ")"
- // << LL_ENDL;
- if(method.empty() || !response)
- {
- return false;
- }
- mState = STATE_READY;
- mURI.assign(uri);
- std::stringstream req;
- req << LLSDRPC_REQUEST_HEADER_1 << method
- << LLSDRPC_REQUEST_HEADER_2;
- LLSDSerialize::toNotation(parameter, req);
- req << LLSDRPC_REQUEST_FOOTER;
- mRequest = req.str();
- mQueue = queue;
- mResponse = response;
- return true;
-}
-
-bool LLSDRPCClient::call(
- const std::string& uri,
- const std::string& method,
- const std::string& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue)
-{
- //LL_INFOS() << "RPC: " << uri << "." << method << "(" << parameter << ")"
- // << LL_ENDL;
- if(method.empty() || parameter.empty() || !response)
- {
- return false;
- }
- mState = STATE_READY;
- mURI.assign(uri);
- std::stringstream req;
- req << LLSDRPC_REQUEST_HEADER_1 << method
- << LLSDRPC_REQUEST_HEADER_2 << parameter
- << LLSDRPC_REQUEST_FOOTER;
- mRequest = req.str();
- mQueue = queue;
- mResponse = response;
- return true;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_CLIENT("SDRPC Client");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCClient::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_CLIENT);
- PUMP_DEBUG;
- if((STATE_NONE == mState) || (!pump))
- {
- // You should have called the call() method already.
- return STATUS_PRECONDITION_NOT_MET;
- }
- EStatus rv = STATUS_DONE;
- switch(mState)
- {
- case STATE_READY:
- {
- PUMP_DEBUG;
-// LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_READY" << LL_ENDL;
- buffer->append(
- channels.out(),
- (U8*)mRequest.c_str(),
- mRequest.length());
- context[CONTEXT_DEST_URI_SD_LABEL] = mURI;
- mState = STATE_WAITING_FOR_RESPONSE;
- break;
- }
- case STATE_WAITING_FOR_RESPONSE:
- {
- PUMP_DEBUG;
- // The input channel has the sd response in it.
- //LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE"
- // << LL_ENDL;
- LLBufferStream resp(channels, buffer.get());
- LLSD sd;
- LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in()));
- LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get();
- if (!response)
- {
- mState = STATE_DONE;
- break;
- }
- response->extractResponse(sd);
- if(EPBQ_PROCESS == mQueue)
- {
- LLPumpIO::chain_t chain;
- chain.push_back(mResponse);
- pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
- }
- else
- {
- pump->respond(mResponse.get());
- }
- mState = STATE_DONE;
- break;
- }
- case STATE_DONE:
- default:
- PUMP_DEBUG;
- LL_INFOS() << "invalid state to process" << LL_ENDL;
- rv = STATUS_ERROR;
- break;
- }
- return rv;
-}
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
deleted file mode 100755
index d097ecdff7..0000000000
--- a/indra/llmessage/llsdrpcclient.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/**
- * @file llsdrpcclient.h
- * @author Phoenix
- * @date 2005-11-05
- * @brief Implementation and helpers for structure data RPC clients.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSDRPCCLIENT_H
-#define LL_LLSDRPCCLIENT_H
-
-/**
- * This file declares classes to encapsulate a basic structured data
- * remote procedure client.
- */
-
-#include "llchainio.h"
-#include "llfiltersd2xmlrpc.h"
-#include "lliopipe.h"
-#if 0
-//#include "llurlrequest.h"
-#endif
-
-/**
- * @class LLSDRPCClientResponse
- * @brief Abstract base class to represent a response from an SD server.
- *
- * This is used as a base class for callbacks generated from an
- * structured data remote procedure call. The
- * <code>extractResponse</code> method will deal with the llsdrpc method
- * call overhead, and keep track of what to call during the next call
- * into <code>process</code>. If you use this as a base class, you
- * need to implement <code>response</code>, <code>fault</code>, and
- * <code>error</code> to do something useful. When in those methods,
- * you can parse and utilize the mReturnValue member data.
- */
-class LLSDRPCResponse : public LLIOPipe
-{
-public:
- LLSDRPCResponse();
- virtual ~LLSDRPCResponse();
-
- /**
- * @brief This method extracts the response out of the sd passed in
- *
- * Any appropriate data found in the sd passed in will be
- * extracted and managed by this object - not copied or cloned. It
- * will still be up to the caller to delete the pointer passed in.
- * @param sd The raw structured data response from the remote server.
- * @return Returns true if this was able to parse the structured data.
- */
- bool extractResponse(const LLSD& sd);
-
-protected:
- /**
- * @brief Method called when the response is ready.
- */
- virtual bool response(LLPumpIO* pump) = 0;
-
- /**
- * @brief Method called when a fault is generated by the remote server.
- */
- virtual bool fault(LLPumpIO* pump) = 0;
-
- /**
- * @brief Method called when there was an error
- */
- virtual bool error(LLPumpIO* pump) = 0;
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- LLSD mReturnValue;
- bool mIsError;
- bool mIsFault;
-};
-
-/**
- * @class LLSDRPCClient
- * @brief Client class for a structured data remote procedure call.
- *
- * This class helps deal with making structured data calls to a remote
- * server. You can visualize the calls as:
- * <code>
- * response = uri.method(parameter)
- * </code>
- * where you pass in everything to <code>call</code> and this class
- * takes care of the rest of the details.
- * In typical usage, you will derive a class from this class and
- * provide an API more useful for the specific application at
- * hand. For example, if you were writing a service to send an instant
- * message, you could create an API for it to send the messsage, and
- * that class would do the work of translating it into the method and
- * parameter, find the destination, and invoke <code>call</call> with
- * a useful implementation of LLSDRPCResponse passed in to handle the
- * response from the network.
- */
-class LLSDRPCClient : public LLIOPipe
-{
-public:
- LLSDRPCClient();
- virtual ~LLSDRPCClient();
-
- /**
- * @brief Enumeration for tracking which queue to process the
- * response.
- */
- enum EPassBackQueue
- {
- EPBQ_PROCESS,
- EPBQ_CALLBACK,
- };
-
- /**
- * @brief Call a method on a remote LLSDRPCServer
- *
- * @param uri The remote object to call, eg,
- * http://localhost/usher. If you are using a factory with a fixed
- * url, the uri passed in will probably be ignored.
- * @param method The method to call on the remote object
- * @param parameter The parameter to pass into the remote
- * object. It is up to the caller to delete the value passed in.
- * @param response The object which gets the response.
- * @param queue Specifies to call the response on the process or
- * callback queue.
- * @return Returns true if this object will be able to make the RPC call.
- */
- bool call(
- const std::string& uri,
- const std::string& method,
- const LLSD& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue);
-
- /**
- * @brief Call a method on a remote LLSDRPCServer
- *
- * @param uri The remote object to call, eg,
- * http://localhost/usher. If you are using a factory with a fixed
- * url, the uri passed in will probably be ignored.
- * @param method The method to call on the remote object
- * @param parameter The seriailized parameter to pass into the
- * remote object.
- * @param response The object which gets the response.
- * @param queue Specifies to call the response on the process or
- * callback queue.
- * @return Returns true if this object will be able to make the RPC call.
- */
- bool call(
- const std::string& uri,
- const std::string& method,
- const std::string& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue);
-
-protected:
- /**
- * @brief Enumeration for tracking client state.
- */
- enum EState
- {
- STATE_NONE,
- STATE_READY,
- STATE_WAITING_FOR_RESPONSE,
- STATE_DONE
- };
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- EState mState;
- std::string mURI;
- std::string mRequest;
- EPassBackQueue mQueue;
- LLIOPipe::ptr_t mResponse;
-};
-
-#if 0
-/**
- * @class LLSDRPCClientFactory
- * @brief Basic implementation for making an SD RPC client factory
- *
- * This class eases construction of a basic sd rpc client. Here is an
- * example of it's use:
- * <code>
- * class LLUsefulService : public LLService { ... }
- * LLService::registerCreator(
- * "useful",
- * LLService::creator_t(new LLSDRPCClientFactory<LLUsefulService>))
- * </code>
- */
-template<class Client>
-class LLSDRPCClientFactory : public LLChainIOFactory
-{
-public:
- LLSDRPCClientFactory() {}
- LLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLSDRPCClientFactory::build" << LL_ENDL;
- LLURLRequest* http(new LLURLRequest(HTTP_POST));
- if(!http->isValid())
- {
- LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
- delete http;
- return false;
- }
-
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
- LLIOPipe::ptr_t http_pipe(http);
- http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);
- if(mURL.empty())
- {
- chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
- }
- else
- {
- http->setURL(mURL);
- }
- chain.push_back(http_pipe);
- chain.push_back(service);
- return true;
- }
-protected:
- std::string mURL;
-};
-#endif
-
-#if 0
-/**
- * @class LLXMLSDRPCClientFactory
- * @brief Basic implementation for making an XMLRPC to SD RPC client factory
- *
- * This class eases construction of a basic sd rpc client which uses
- * xmlrpc as a serialization grammar. Here is an example of it's use:
- * <code>
- * class LLUsefulService : public LLService { ... }
- * LLService::registerCreator(
- * "useful",
- * LLService::creator_t(new LLXMLSDRPCClientFactory<LLUsefulService>))
- * </code>
- */
-template<class Client>
-class LLXMLSDRPCClientFactory : public LLChainIOFactory
-{
-public:
- LLXMLSDRPCClientFactory() {}
- LLXMLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCClientFactory::build" << LL_ENDL;
-
- LLURLRequest* http(new LLURLRequest(HTTP_POST));
- if(!http->isValid())
- {
- LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
- delete http;
- return false ;
- }
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
- LLIOPipe::ptr_t http_pipe(http);
- http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
- if(mURL.empty())
- {
- chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
- }
- else
- {
- http->setURL(mURL);
- }
- chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest(NULL)));
- chain.push_back(http_pipe);
- chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
- chain.push_back(service);
- return true;
- }
-protected:
- std::string mURL;
-};
-#endif
-
-#endif // LL_LLSDRPCCLIENT_H
diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp
deleted file mode 100755
index c3ed19889e..0000000000
--- a/indra/llmessage/llsdrpcserver.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * @file llsdrpcserver.cpp
- * @author Phoenix
- * @date 2005-10-11
- * @brief Implementation of the LLSDRPCServer and related classes.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llsdrpcserver.h"
-
-#include "llbuffer.h"
-#include "llbufferstream.h"
-#include "llfasttimer.h"
-#include "llpumpio.h"
-#include "llsdserialize.h"
-#include "llstl.h"
-
-static const char FAULT_PART_1[] = "{'fault':{'code':i";
-static const char FAULT_PART_2[] = ", 'description':'";
-static const char FAULT_PART_3[] = "'}}";
-
-static const char RESPONSE_PART_1[] = "{'response':";
-static const char RESPONSE_PART_2[] = "}";
-
-static const S32 FAULT_GENERIC = 1000;
-static const S32 FAULT_METHOD_NOT_FOUND = 1001;
-
-static const std::string LLSDRPC_METHOD_SD_NAME("method");
-static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter");
-
-
-/**
- * LLSDRPCServer
- */
-LLSDRPCServer::LLSDRPCServer() :
- mState(LLSDRPCServer::STATE_NONE),
- mPump(NULL),
- mLock(0)
-{
-}
-
-LLSDRPCServer::~LLSDRPCServer()
-{
- std::for_each(
- mMethods.begin(),
- mMethods.end(),
- llcompose1(
- DeletePointerFunctor<LLSDRPCMethodCallBase>(),
- llselect2nd<method_map_t::value_type>()));
- std::for_each(
- mCallbackMethods.begin(),
- mCallbackMethods.end(),
- llcompose1(
- DeletePointerFunctor<LLSDRPCMethodCallBase>(),
- llselect2nd<method_map_t::value_type>()));
-}
-
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::deferredResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data) {
- // subclass should provide a sane implementation
- return ESDRPCS_DONE;
-}
-
-void LLSDRPCServer::clearLock()
-{
- if(mLock && mPump)
- {
- mPump->clearLock(mLock);
- mPump = NULL;
- mLock = 0;
- }
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_SERVER("SDRPC Server");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCServer::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_SERVER);
- PUMP_DEBUG;
-// LL_DEBUGS() << "LLSDRPCServer::process_impl" << LL_ENDL;
- // Once we have all the data, We need to read the sd on
- // the the in channel, and respond on the out channel
- if(!eos) return STATUS_BREAK;
- if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
-
- std::string method_name;
- LLIOPipe::EStatus status = STATUS_DONE;
-
- switch(mState)
- {
- case STATE_DEFERRED:
- PUMP_DEBUG;
- if(ESDRPCS_DONE != deferredResponse(channels, buffer.get()))
- {
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "deferred response failed.");
- }
- mState = STATE_DONE;
- return STATUS_DONE;
-
- case STATE_DONE:
-// LL_DEBUGS() << "STATE_DONE" << LL_ENDL;
- break;
- case STATE_CALLBACK:
-// LL_DEBUGS() << "STATE_CALLBACK" << LL_ENDL;
- PUMP_DEBUG;
- method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
- if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
- {
- if(ESDRPCS_DONE != callbackMethod(
- method_name,
- mRequest[LLSDRPC_PARAMETER_SD_NAME],
- channels,
- buffer.get()))
- {
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Callback method call failed.");
- }
- }
- else
- {
- // this should never happen, since we should not be in
- // this state unless we originally found a method and
- // params during the first call to process.
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Invalid LLSDRPC sever state - callback without method.");
- }
- pump->clearLock(mLock);
- mLock = 0;
- mState = STATE_DONE;
- break;
- case STATE_NONE:
-// LL_DEBUGS() << "STATE_NONE" << LL_ENDL;
- default:
- {
- // First time we got here - process the SD request, and call
- // the method.
- PUMP_DEBUG;
- LLBufferStream istr(channels, buffer.get());
- mRequest.clear();
- LLSDSerialize::fromNotation(
- mRequest,
- istr,
- buffer->count(channels.in()));
-
- // { 'method':'...', 'parameter': ... }
- method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
- if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
- {
- ESDRPCSStatus rv = callMethod(
- method_name,
- mRequest[LLSDRPC_PARAMETER_SD_NAME],
- channels,
- buffer.get());
- switch(rv)
- {
- case ESDRPCS_DEFERRED:
- mPump = pump;
- mLock = pump->setLock();
- mState = STATE_DEFERRED;
- status = STATUS_BREAK;
- break;
-
- case ESDRPCS_CALLBACK:
- {
- mState = STATE_CALLBACK;
- LLPumpIO::LLLinkInfo link;
- link.mPipe = LLIOPipe::ptr_t(this);
- link.mChannels = channels;
- LLPumpIO::links_t links;
- links.push_back(link);
- pump->respond(links, buffer, context);
- mLock = pump->setLock();
- status = STATUS_BREAK;
- break;
- }
- case ESDRPCS_DONE:
- mState = STATE_DONE;
- break;
- case ESDRPCS_ERROR:
- default:
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Method call failed.");
- break;
- }
- }
- else
- {
- // send a fault
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Unable to find method and parameter in request.");
- }
- break;
- }
- }
-
- PUMP_DEBUG;
- return status;
-}
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::callMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response)
-{
- // Try to find the method in the method table.
- ESDRPCSStatus rv = ESDRPCS_DONE;
- method_map_t::iterator it = mMethods.find(method);
- if(it != mMethods.end())
- {
- rv = (*it).second->call(params, channels, response);
- }
- else
- {
- it = mCallbackMethods.find(method);
- if(it == mCallbackMethods.end())
- {
- // method not found.
- std::ostringstream message;
- message << "rpc server unable to find method: " << method;
- buildFault(
- channels,
- response,
- FAULT_METHOD_NOT_FOUND,
- message.str());
- }
- else
- {
- // we found it in the callback methods - tell the process
- // to coordinate calling on the pump callback.
- return ESDRPCS_CALLBACK;
- }
- }
- return rv;
-}
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::callbackMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response)
-{
- // Try to find the method in the callback method table.
- ESDRPCSStatus rv = ESDRPCS_DONE;
- method_map_t::iterator it = mCallbackMethods.find(method);
- if(it != mCallbackMethods.end())
- {
- rv = (*it).second->call(params, channels, response);
- }
- else
- {
- std::ostringstream message;
- message << "pcserver unable to find callback method: " << method;
- buildFault(
- channels,
- response,
- FAULT_METHOD_NOT_FOUND,
- message.str());
- }
- return rv;
-}
-
-// static
-void LLSDRPCServer::buildFault(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- S32 code,
- const std::string& msg)
-{
- LLBufferStream ostr(channels, data);
- ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
- LL_INFOS() << "LLSDRPCServer::buildFault: " << code << ", " << msg << LL_ENDL;
-}
-
-// static
-void LLSDRPCServer::buildResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- const LLSD& response)
-{
- LLBufferStream ostr(channels, data);
- ostr << RESPONSE_PART_1;
- LLSDSerialize::toNotation(response, ostr);
- ostr << RESPONSE_PART_2;
-#if LL_DEBUG
- std::ostringstream debug_ostr;
- debug_ostr << "LLSDRPCServer::buildResponse: ";
- LLSDSerialize::toNotation(response, debug_ostr);
- LL_INFOS() << debug_ostr.str() << LL_ENDL;
-#endif
-}
diff --git a/indra/llmessage/llsdrpcserver.h b/indra/llmessage/llsdrpcserver.h
deleted file mode 100755
index 415bd31c26..0000000000
--- a/indra/llmessage/llsdrpcserver.h
+++ /dev/null
@@ -1,360 +0,0 @@
-/**
- * @file llsdrpcserver.h
- * @author Phoenix
- * @date 2005-10-11
- * @brief Declaration of the structured data remote procedure call server.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSDRPCSERVER_H
-#define LL_LLSDRPCSERVER_H
-
-/**
- * I've set this up to be pretty easy to use when you want to make a
- * structured data rpc server which responds to methods by
- * name. Derive a class from the LLSDRPCServer, and during
- * construction (or initialization if you have the luxury) map method
- * names to pointers to member functions. This will look a lot like:
- *
- * <code>
- * class LLMessageAgents : public LLSDRPCServer {<br>
- * public:<br>
- * typedef LLSDRPCServer<LLUsher> mem_fn_t;<br>
- * LLMessageAgents() {<br>
- * mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br>
- * mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br>
- * }<br>
- * protected:<br>
- * rpc_IM(const LLSD& params,
- * const LLChannelDescriptors& channels,
- * LLBufferArray* data)
- * {...}<br>
- * rpc_Alert(const LLSD& params,
- * const LLChannelDescriptors& channels,
- * LLBufferArray* data)
- * {...}<br>
- * };<br>
- * </code>
- *
- * The params are an array where each element in the array is a single
- * parameter in the call.
- *
- * It is up to you to pack a valid serialized llsd response into the
- * data object passed into the method, but you can use the helper
- * methods below to help.
- */
-
-#include <map>
-#include "lliopipe.h"
-#include "lliohttpserver.h"
-#include "llfiltersd2xmlrpc.h"
-
-class LLSD;
-
-/**
- * @brief Enumeration for specifying server method call status. This
- * enumeration controls how the server class will manage the pump
- * process/callback mechanism.
- */
-enum ESDRPCSStatus
-{
- // The call went ok, but the response is not yet ready. The
- // method will arrange for the clearLock() call to be made at
- // a later date, after which, once the chain is being pumped
- // again, deferredResponse() will be called to gather the result
- ESDRPCS_DEFERRED,
-
- // The LLSDRPCServer would like to handle the method on the
- // callback queue of the pump.
- ESDRPCS_CALLBACK,
-
- // The method call finished and generated output.
- ESDRPCS_DONE,
-
- // Method failed for some unspecified reason - you should avoid
- // this. A generic fault will be sent to the output.
- ESDRPCS_ERROR,
-
- ESDRPCS_COUNT,
-};
-
-/**
- * @class LLSDRPCMethodCallBase
- * @brief Base class for calling a member function in an sd rpcserver
- * implementation.
- */
-class LLSDRPCMethodCallBase
-{
-public:
- LLSDRPCMethodCallBase() {}
- virtual ~LLSDRPCMethodCallBase() {}
-
- virtual ESDRPCSStatus call(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response) = 0;
-protected:
-};
-
-/**
- * @class LLSDRPCMethodCall
- * @brief Class which implements member function calls.
- */
-template<class Server>
-class LLSDRPCMethodCall : public LLSDRPCMethodCallBase
-{
-public:
- typedef ESDRPCSStatus (Server::*mem_fn)(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
- LLSDRPCMethodCall(Server* s, mem_fn fn) :
- mServer(s),
- mMemFn(fn)
- {
- }
- virtual ~LLSDRPCMethodCall() {}
- virtual ESDRPCSStatus call(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data)
- {
- return (*mServer.*mMemFn)(params, channels, data);
- }
-
-protected:
- Server* mServer;
- mem_fn mMemFn;
- //bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data);
-};
-
-
-/**
- * @class LLSDRPCServer
- * @brief Basic implementation of a structure data rpc server
- *
- * The rpc server is also designed to appropriately straddle the pump
- * <code>process()</code> and <code>callback()</code> to specify which
- * thread you want to work on when handling a method call. The
- * <code>mMethods</code> methods are called from
- * <code>process()</code>, while the <code>mCallbackMethods</code> are
- * called when a pump is in a <code>callback()</code> cycle.
- */
-class LLSDRPCServer : public LLIOPipe
-{
-public:
- LLSDRPCServer();
- virtual ~LLSDRPCServer();
-
- /**
- * enumeration for generic fault codes
- */
- enum
- {
- FAULT_BAD_REQUEST = 2000,
- FAULT_NO_RESPONSE = 2001,
- };
-
- /**
- * @brief Call this method to return an rpc fault.
- *
- * @param channel The channel for output on the data buffer
- * @param data buffer which will recieve the final output
- * @param code The fault code
- * @param msg The fault message
- */
- static void buildFault(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- S32 code,
- const std::string& msg);
-
- /**
- * @brief Call this method to build an rpc response.
- *
- * @param channel The channel for output on the data buffer
- * @param data buffer which will recieve the final output
- * @param response The return value from the method call
- */
- static void buildResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- const LLSD& response);
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
-
- /**
- * @brief Enumeration to track the state of the rpc server instance
- */
- enum EState
- {
- STATE_NONE,
- STATE_CALLBACK,
- STATE_DEFERRED,
- STATE_DONE
- };
-
- /**
- * @brief This method is called when an http post comes in.
- *
- * The default behavior is to look at the method name, look up the
- * method in the method table, and call it. If the method is not
- * found, this function will build a fault response. You can
- * implement your own version of this function if you want to hard
- * wire some behavior or optimize things a bit.
- * @param method The method name being called
- * @param params The parameters
- * @param channel The channel for output on the data buffer
- * @param data The http data
- * @return Returns the status of the method call, done/deferred/etc
- */
- virtual ESDRPCSStatus callMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- /**
- * @brief This method is called when a pump callback is processed.
- *
- * The default behavior is to look at the method name, look up the
- * method in the callback method table, and call it. If the method
- * is not found, this function will build a fault response. You
- * can implement your own version of this function if you want to
- * hard wire some behavior or optimize things a bit.
- * @param method The method name being called
- * @param params The parameters
- * @param channel The channel for output on the data buffer
- * @param data The http data
- * @return Returns the status of the method call, done/deferred/etc
- */
- virtual ESDRPCSStatus callbackMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- /**
- * @brief Called after a deferred service is unlocked
- *
- * If a method returns ESDRPCS_DEFERRED, then the service chain
- * will be locked and not processed until some other system calls
- * clearLock() on the service instance again. At that point,
- * once the pump starts processing the chain again, this method
- * will be called so the service can output the final result
- * into the buffers.
- */
- virtual ESDRPCSStatus deferredResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- // donovan put this public here 7/27/06
-public:
- /**
- * @brief unlock a service that as ESDRPCS_DEFERRED
- */
- void clearLock();
-
-protected:
- EState mState;
- LLSD mRequest;
- LLPumpIO* mPump;
- S32 mLock;
- typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t;
- method_map_t mMethods;
- method_map_t mCallbackMethods;
-};
-
-/**
- * @name Helper Templates for making LLHTTPNodes
- *
- * These templates help in creating nodes for handing a service from
- * either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer.
- *
- * To use it:
- * \code
- * class LLUsefulServer : public LLSDRPCServer { ... }
- *
- * LLHTTPNode& root = LLCreateHTTPWireServer(...);
- * root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>);
- * root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>);
- * \endcode
- */
-//@{
-
-template<class Server>
-class LLSDRPCServerFactory : public LLChainIOFactory
-{
-public:
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL;
- chain.push_back(LLIOPipe::ptr_t(new Server));
- return true;
- }
-};
-
-template<class Server>
-class LLSDRPCNode : public LLHTTPNodeForFactory<
- LLSDRPCServerFactory<Server> >
-{
-};
-
-template<class Server>
-class LLXMLRPCServerFactory : public LLChainIOFactory
-{
-public:
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL;
- chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
- chain.push_back(LLIOPipe::ptr_t(new Server));
- chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
- return true;
- }
-};
-
-template<class Server>
-class LLXMLRPCNode : public LLHTTPNodeForFactory<
- LLXMLRPCServerFactory<Server> >
-{
-};
-
-//@}
-
-#endif // LL_LLSDRPCSERVER_H
diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp
index 5bd1112cfe..33944f7883 100755
--- a/indra/llmessage/lltrustedmessageservice.cpp
+++ b/indra/llmessage/lltrustedmessageservice.cpp
@@ -30,6 +30,7 @@
#include "llhost.h"
#include "llmessageconfig.h"
#include "message.h"
+#include "llhttpconstants.h"
bool LLTrustedMessageService::validate(const std::string& name, LLSD& context)
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
deleted file mode 100755
index 1294379eca..0000000000
--- a/indra/llmessage/llurlrequest.cpp
+++ /dev/null
@@ -1,783 +0,0 @@
-/**
- * @file llurlrequest.cpp
- * @author Phoenix
- * @date 2005-04-28
- * @brief Implementation of the URLRequest class and related classes.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llurlrequest.h"
-
-#include <algorithm>
-#include <openssl/x509_vfy.h>
-#include <openssl/ssl.h>
-#include "llcurl.h"
-#include "llfasttimer.h"
-#include "llioutil.h"
-#include "llproxy.h"
-#include "llpumpio.h"
-#include "llsd.h"
-#include "llstring.h"
-#include "apr_env.h"
-#include "llapr.h"
-
-/**
- * String constants
- */
-const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
-const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
-
-// These are defined in llhttpnode.h/llhttpnode.cpp
-extern const std::string CONTEXT_REQUEST;
-extern const std::string CONTEXT_RESPONSE;
-
-static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
-
-/**
- * class LLURLRequestDetail
- */
-class LLURLRequestDetail
-{
-public:
- LLURLRequestDetail();
- ~LLURLRequestDetail();
- std::string mURL;
- LLCurlEasyRequest* mCurlRequest;
- LLIOPipe::buffer_ptr_t mResponseBuffer;
- LLChannelDescriptors mChannels;
- U8* mLastRead;
- U32 mBodyLimit;
- S32 mByteAccumulator;
- bool mIsBodyLimitSet;
- LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
-};
-
-LLURLRequestDetail::LLURLRequestDetail() :
- mCurlRequest(NULL),
- mLastRead(NULL),
- mBodyLimit(0),
- mByteAccumulator(0),
- mIsBodyLimitSet(false),
- mSSLVerifyCallback(NULL)
-{
- mCurlRequest = new LLCurlEasyRequest();
-
- if(!mCurlRequest->isValid()) //failed.
- {
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- }
-}
-
-LLURLRequestDetail::~LLURLRequestDetail()
-{
- delete mCurlRequest;
- mLastRead = NULL;
-}
-
-void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
-{
- mDetail->mSSLVerifyCallback = callback;
- mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
-}
-
-
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validation
-
-CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
-{
- LLURLRequest *req = (LLURLRequest *)param;
- if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
- {
- SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL);
- return CURLE_OK;
- }
- SSL_CTX * ctx = (SSL_CTX *) sslctx;
- // disable any default verification for server certs
- SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
- // set the verification callback.
- SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req);
- // the calls are void
- return CURLE_OK;
-
-}
-
-/**
- * class LLURLRequest
- */
-
-
-LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) :
- mAction(action),
- mFollowRedirects(follow_redirects)
-{
- initialize();
-}
-
-LLURLRequest::LLURLRequest(
- EHTTPMethod action,
- const std::string& url,
- bool follow_redirects /* = true */) :
- mAction(action),
- mFollowRedirects(follow_redirects)
-{
- initialize();
- setURL(url);
-}
-
-LLURLRequest::~LLURLRequest()
-{
- delete mDetail;
- mDetail = NULL ;
-}
-
-void LLURLRequest::setURL(const std::string& url)
-{
- mDetail->mURL = url;
- if (url.empty())
- {
- LL_WARNS() << "empty URL specified" << LL_ENDL;
- }
-}
-
-const std::string& LLURLRequest::getURL() const
-{
- return mDetail->mURL;
-}
-
-void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */)
-{
- mDetail->mCurlRequest->slist_append(header, value);
-}
-
-void LLURLRequest::addHeaderRaw(const char* header)
-{
- mDetail->mCurlRequest->slist_append(header);
-}
-
-void LLURLRequest::setBodyLimit(U32 size)
-{
- mDetail->mBodyLimit = size;
- mDetail->mIsBodyLimitSet = true;
-}
-
-void LLURLRequest::setCallback(LLURLRequestComplete* callback)
-{
- mCompletionCallback = callback;
- mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback);
-}
-
-// Added to mitigate the effect of libcurl looking
-// for the ALL_PROXY and http_proxy env variables
-// and deciding to insert a Pragma: no-cache
-// header! The only usage of this method at the
-// time of this writing is in llhttpclient.cpp
-// in the request() method, where this method
-// is called with use_proxy = FALSE
-void LLURLRequest::useProxy(bool use_proxy)
-{
- static char *env_proxy;
-
- if (use_proxy && (env_proxy == NULL))
- {
- apr_status_t status;
- LLAPRPool pool;
- status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
- if (status != APR_SUCCESS)
- {
- status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
- }
- if (status != APR_SUCCESS)
- {
- use_proxy = FALSE;
- }
- }
-
-
- LL_DEBUGS() << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL;
-
- if (env_proxy && use_proxy)
- {
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
- }
- else
- {
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, "");
- }
-}
-
-void LLURLRequest::useProxy(const std::string &proxy)
-{
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
-}
-
-void LLURLRequest::allowCookies()
-{
- mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
-}
-
-//virtual
-bool LLURLRequest::isValid()
-{
- return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();
-}
-
-// virtual
-LLIOPipe::EStatus LLURLRequest::handleError(
- LLIOPipe::EStatus status,
- LLPumpIO* pump)
-{
- if(!isValid())
- {
- return STATUS_EXPIRED ;
- }
-
- if(mCompletionCallback && pump)
- {
- LLURLRequestComplete* complete = NULL;
- complete = (LLURLRequestComplete*)mCompletionCallback.get();
- complete->httpStatus(
- HTTP_INTERNAL_ERROR,
- LLIOPipe::lookupStatusString(status));
- complete->responseStatus(status);
- pump->respond(complete);
- mCompletionCallback = NULL;
- }
- return status;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST("URL Request");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result");
-static LLTrace::BlockTimerStatHandle FTM_URL_PERFORM("Perform");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond");
-static LLTrace::BlockTimerStatHandle FTM_URL_ADJUST_TIMEOUT("Adjust Timeout");
-
-// virtual
-LLIOPipe::EStatus LLURLRequest::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST);
- PUMP_DEBUG;
- //LL_INFOS() << "LLURLRequest::process_impl()" << LL_ENDL;
- if (!buffer) return STATUS_ERROR;
-
- // we're still waiting or prcessing, check how many
- // bytes we have accumulated.
- const S32 MIN_ACCUMULATION = 100000;
- if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
- {
- LL_RECORD_BLOCK_TIME(FTM_URL_ADJUST_TIMEOUT);
- // This is a pretty sloppy calculation, but this
- // tries to make the gross assumption that if data
- // is coming in at 56kb/s, then this transfer will
- // probably succeed. So, if we're accumlated
- // 100,000 bytes (MIN_ACCUMULATION) then let's
- // give this client another 2s to complete.
- const F32 TIMEOUT_ADJUSTMENT = 2.0f;
- mDetail->mByteAccumulator = 0;
- pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
- LL_DEBUGS() << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << LL_ENDL;
- if (mState == STATE_INITIALIZED)
- {
- LL_INFOS() << "LLURLRequest adjustTimeoutSeconds called during upload" << LL_ENDL;
- }
- }
-
- switch(mState)
- {
- case STATE_INITIALIZED:
- {
- PUMP_DEBUG;
- // We only need to wait for input if we are uploading
- // something.
- if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos)
- {
- // we're waiting to get all of the information
- return STATUS_BREAK;
- }
-
- // *FIX: bit of a hack, but it should work. The configure and
- // callback method expect this information to be ready.
- mDetail->mResponseBuffer = buffer;
- mDetail->mChannels = channels;
- if(!configure())
- {
- return STATUS_ERROR;
- }
- mState = STATE_WAITING_FOR_RESPONSE;
-
- // *FIX: Maybe we should just go to the next state now...
- return STATUS_BREAK;
- }
- case STATE_WAITING_FOR_RESPONSE:
- case STATE_PROCESSING_RESPONSE:
- {
- PUMP_DEBUG;
- LLIOPipe::EStatus status = STATUS_BREAK;
- {
- LL_RECORD_BLOCK_TIME(FTM_URL_PERFORM);
- if(!mDetail->mCurlRequest->wait())
- {
- return status ;
- }
- }
-
- bool keep_looping = true;
- while(keep_looping)
- {
- CURLcode result;
-
- bool newmsg = false;
- {
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST_GET_RESULT);
- newmsg = mDetail->mCurlRequest->getResult(&result);
- }
-
- if(!newmsg)
- {
- // keep processing
- break;
- }
-
-
- mState = STATE_HAVE_RESPONSE;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- switch(result)
- {
- case CURLE_OK:
- case CURLE_WRITE_ERROR:
- // NB: The error indication means that we stopped the
- // writing due the body limit being reached
- if(mCompletionCallback && pump)
- {
- LLURLRequestComplete* complete = NULL;
- complete = (LLURLRequestComplete*)
- mCompletionCallback.get();
- complete->responseStatus(
- result == CURLE_OK
- ? STATUS_OK : STATUS_STOP);
- LLPumpIO::links_t chain;
- LLPumpIO::LLLinkInfo link;
- link.mPipe = mCompletionCallback;
- link.mChannels = LLBufferArray::makeChannelConsumer(
- channels);
- chain.push_back(link);
- {
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_PUMP_RESPOND);
- pump->respond(chain, buffer, context);
- }
- mCompletionCallback = NULL;
- }
- break;
- case CURLE_FAILED_INIT:
- case CURLE_COULDNT_CONNECT:
- status = STATUS_NO_CONNECTION;
- keep_looping = false;
- break;
- default: // CURLE_URL_MALFORMAT
- LL_WARNS() << "URLRequest Error: " << result
- << ", "
- << LLCurl::strerror(result)
- << ", "
- << (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
- << LL_ENDL;
- status = STATUS_ERROR;
- keep_looping = false;
- break;
- }
- }
- return status;
- }
- case STATE_HAVE_RESPONSE:
- PUMP_DEBUG;
- // we already stuffed everything into channel in in the curl
- // callback, so we are done.
- eos = true;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- return STATUS_DONE;
-
- default:
- PUMP_DEBUG;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- return STATUS_ERROR;
- }
-}
-
-void LLURLRequest::initialize()
-{
- mState = STATE_INITIALIZED;
- mDetail = new LLURLRequestDetail;
-
- if(!isValid())
- {
- return ;
- }
-
- mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
- mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
- mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
- mRequestTransferedBytes = 0;
- mResponseTransferedBytes = 0;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_URL_REQUEST_CONFIGURE("URL Configure");
-bool LLURLRequest::configure()
-{
- LL_RECORD_BLOCK_TIME(FTM_URL_REQUEST_CONFIGURE);
-
- bool rv = false;
- S32 bytes = mDetail->mResponseBuffer->countAfter(
- mDetail->mChannels.in(),
- NULL);
- switch(mAction)
- {
- case HTTP_HEAD:
- mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
- mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
- if (mFollowRedirects)
- {
- mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
- }
- rv = true;
- break;
- case HTTP_GET:
- mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
- if (mFollowRedirects)
- {
- mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
- }
-
- // Set Accept-Encoding to allow response compression
- mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- rv = true;
- break;
-
- case HTTP_PUT:
- // Disable the expect http 1.1 extension. POST and PUT default
- // to turning this on, and I am not too sure what it means.
- addHeader(HTTP_OUT_HEADER_EXPECT);
-
- mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
- mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
- rv = true;
- break;
-
- case HTTP_PATCH:
- // Disable the expect http 1.1 extension. POST and PUT default
- // to turning this on, and I am not too sure what it means.
- addHeader(HTTP_OUT_HEADER_EXPECT);
-
- mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
- mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
- mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");
- rv = true;
- break;
-
- case HTTP_POST:
- // Disable the expect http 1.1 extension. POST and PUT default
- // to turning this on, and I am not too sure what it means.
- addHeader(HTTP_OUT_HEADER_EXPECT);
-
- // Disable the content type http header.
- // *FIX: what should it be?
- addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);
-
- // Set the handle for an http post
- mDetail->mCurlRequest->setPost(NULL, bytes);
-
- // Set Accept-Encoding to allow response compression
- mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- rv = true;
- break;
-
- case HTTP_DELETE:
- // Set the handle for an http delete
- mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
- rv = true;
- break;
-
- case HTTP_COPY:
- // Set the handle for an http copy
- mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY");
- rv = true;
- break;
-
- case HTTP_MOVE:
- // Set the handle for an http move
- mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
- // *NOTE: should we check for the Destination header?
- rv = true;
- break;
-
- default:
- LL_WARNS() << "Unhandled URLRequest action: " << mAction << LL_ENDL;
- break;
- }
- if(rv)
- {
- mDetail->mCurlRequest->sendRequest(mDetail->mURL);
- }
- return rv;
-}
-
-// static
-size_t LLURLRequest::downCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user)
-{
- LLURLRequest* req = (LLURLRequest*)user;
- if(STATE_WAITING_FOR_RESPONSE == req->mState)
- {
- req->mState = STATE_PROCESSING_RESPONSE;
- }
- U32 bytes = size * nmemb;
- if (req->mDetail->mIsBodyLimitSet)
- {
- if (bytes > req->mDetail->mBodyLimit)
- {
- bytes = req->mDetail->mBodyLimit;
- req->mDetail->mBodyLimit = 0;
- }
- else
- {
- req->mDetail->mBodyLimit -= bytes;
- }
- }
-
- req->mDetail->mResponseBuffer->append(
- req->mDetail->mChannels.out(),
- (U8*)data,
- bytes);
- req->mResponseTransferedBytes += bytes;
- req->mDetail->mByteAccumulator += bytes;
- return bytes;
-}
-
-// static
-size_t LLURLRequest::upCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user)
-{
- LLURLRequest* req = (LLURLRequest*)user;
- S32 bytes = llmin(
- (S32)(size * nmemb),
- req->mDetail->mResponseBuffer->countAfter(
- req->mDetail->mChannels.in(),
- req->mDetail->mLastRead));
- req->mDetail->mLastRead = req->mDetail->mResponseBuffer->readAfter(
- req->mDetail->mChannels.in(),
- req->mDetail->mLastRead,
- (U8*)data,
- bytes);
- req->mRequestTransferedBytes += bytes;
- return bytes;
-}
-
-static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
-{
- const char* header_line = (const char*)data;
- size_t header_len = size * nmemb;
- LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
-
- if (!complete || !header_line)
- {
- return header_len;
- }
-
- // *TODO: This should be a utility in llstring.h: isascii()
- for (size_t i = 0; i < header_len; ++i)
- {
- if (header_line[i] < 0)
- {
- return header_len;
- }
- }
-
- std::string header(header_line, header_len);
-
- // Per HTTP spec the first header line must be the status line.
- if (header.substr(0,5) == "HTTP/")
- {
- std::string::iterator end = header.end();
- std::string::iterator pos1 = std::find(header.begin(), end, ' ');
- if (pos1 != end) ++pos1;
- std::string::iterator pos2 = std::find(pos1, end, ' ');
- if (pos2 != end) ++pos2;
- std::string::iterator pos3 = std::find(pos2, end, '\r');
-
- std::string version(header.begin(), pos1);
- std::string status(pos1, pos2);
- std::string reason(pos2, pos3);
-
- S32 status_code = atoi(status.c_str());
- if (status_code > 0)
- {
- complete->httpStatus(status_code, reason);
- return header_len;
- }
- }
-
- std::string::iterator sep = std::find(header.begin(),header.end(),':');
-
- if (sep != header.end())
- {
- std::string key(header.begin(), sep);
- std::string value(sep + 1, header.end());
-
- key = utf8str_tolower(utf8str_trim(key));
- value = utf8str_trim(value);
-
- complete->header(key, value);
- }
- else
- {
- LLStringUtil::trim(header);
- if (!header.empty())
- {
- LL_WARNS() << "Unable to parse header: " << header << LL_ENDL;
- }
- }
-
- return header_len;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_EXTRACTOR("URL Extractor");
-/**
- * LLContextURLExtractor
- */
-// virtual
-LLIOPipe::EStatus LLContextURLExtractor::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_EXTRACTOR);
- PUMP_DEBUG;
- // The destination host is in the context.
- if(context.isUndefined() || !mRequest)
- {
- return STATUS_PRECONDITION_NOT_MET;
- }
-
- // copy in to out, since this just extract the URL and does not
- // actually change the data.
- LLChangeChannel change(channels.in(), channels.out());
- std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
-
- // find the context url
- if(context.has(CONTEXT_DEST_URI_SD_LABEL))
- {
- mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString());
- return STATUS_DONE;
- }
- return STATUS_ERROR;
-}
-
-
-/**
- * LLURLRequestComplete
- */
-LLURLRequestComplete::LLURLRequestComplete() :
- mRequestStatus(LLIOPipe::STATUS_ERROR)
-{
-}
-
-// virtual
-LLURLRequestComplete::~LLURLRequestComplete()
-{
-}
-
-//virtual
-void LLURLRequestComplete::header(const std::string& header, const std::string& value)
-{
-}
-
-//virtual
-void LLURLRequestComplete::complete(const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer)
-{
- if(STATUS_OK == mRequestStatus)
- {
- response(channels, buffer);
- }
- else
- {
- noResponse();
- }
-}
-
-//virtual
-void LLURLRequestComplete::response(const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer)
-{
- LL_WARNS() << "LLURLRequestComplete::response default implementation called"
- << LL_ENDL;
-}
-
-//virtual
-void LLURLRequestComplete::noResponse()
-{
- LL_WARNS() << "LLURLRequestComplete::noResponse default implementation called"
- << LL_ENDL;
-}
-
-void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status)
-{
- mRequestStatus = status;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_COMPLETE("URL Complete");
-// virtual
-LLIOPipe::EStatus LLURLRequestComplete::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_COMPLETE);
- PUMP_DEBUG;
- complete(channels, buffer);
- return STATUS_OK;
-}
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
deleted file mode 100755
index 88fccd4bf6..0000000000
--- a/indra/llmessage/llurlrequest.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/**
- * @file llurlrequest.h
- * @author Phoenix
- * @date 2005-04-21
- * @brief Declaration of url based requests on pipes.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLURLREQUEST_H
-#define LL_LLURLREQUEST_H
-
-/**
- * This file holds the declaration of useful classes for dealing with
- * url based client requests.
- */
-
-#include <string>
-#include "lliopipe.h"
-#include "llchainio.h"
-#include "llerror.h"
-#include <openssl/x509_vfy.h>
-#include "llcurl.h"
-
-
-/**
- * External constants
- */
-extern const std::string CONTEXT_DEST_URI_SD_LABEL;
-extern const std::string CONTEXT_TRANSFERED_BYTES;
-
-class LLURLRequestDetail;
-
-class LLURLRequestComplete;
-
-/**
- * @class LLURLRequest
- * @brief Class to handle url based requests.
- * @see LLIOPipe
- *
- * Currently, this class is implemented on top of curl. From the
- * vantage of a programmer using this class, you do not care so much,
- * but it's useful to know since in order to accomplish 'non-blocking'
- * behavior, we have to use a more expensive curl interface which can
- * still block if the server enters a half-accepted state. It would be
- * worth the time and effort to eventually port this to a raw client
- * socket.
- */
-class LLURLRequest : public LLIOPipe
-{
- LOG_CLASS(LLURLRequest);
-public:
- typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
-
- /**
- * @brief Constructor.
- *
- * @param action One of the EHTTPMethod enumerations.
- */
- LLURLRequest(EHTTPMethod action, bool follow_redirects = true);
-
- /**
- * @brief Constructor.
- *
- * @param action One of the EHTTPMethod enumerations.
- * @param url The url of the request. It should already be encoded.
- */
- LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true);
-
- /**
- * @brief Destructor.
- */
- virtual ~LLURLRequest();
-
- /* @name Instance methods
- */
- //@{
- /**
- * @brief Set the url for the request
- *
- * This method assumes the url is encoded appropriately for the
- * request.
- * The url must be set somehow before the first call to process(),
- * or the url will not be set correctly.
- *
- */
- void setURL(const std::string& url);
- const std::string& getURL() const;
- /**
- * @brief Add a header to the http post.
- *
- * This provides a raw interface if you know what kind of request you
- * will be making during construction of this instance. All
- * required headers will be automatically constructed, so this is
- * usually useful for encoding parameters.
- */
- void addHeader(const std::string& header, const std::string& value = "");
- void addHeaderRaw(const char* header);
-
- /**
- * @brief Check remote server certificate signed by a known root CA.
- *
- * Set whether request will check that remote server
- * certificates are signed by a known root CA when using HTTPS.
- */
- void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param);
-
-
- /**
- * @brief Return at most size bytes of body.
- *
- * If the body had more bytes than this limit, they will not be
- * returned and the connection closed. In this case, STATUS_STOP
- * will be passed to responseStatus();
- */
- void setBodyLimit(U32 size);
-
- /**
- * @brief Set a completion callback for this URLRequest.
- *
- * The callback is added to this URLRequet's pump when either the
- * entire buffer is known or an error like timeout or connection
- * refused has happened. In the case of a complete transfer, this
- * object builds a response chain such that the callback and the
- * next process consumer get to read the output.
- *
- * This setup is a little fragile since the url request consumer
- * might not just read the data - it may do a channel change,
- * which invalidates the input to the callback, but it works well
- * in practice.
- */
- void setCallback(LLURLRequestComplete* callback);
- //@}
-
- /* @name LLIOPipe virtual implementations
- */
-
- /**
- * @ brief Turn off (or on) the CURLOPT_PROXY header.
- */
- void useProxy(bool use_proxy);
-
- /**
- * @ brief Set the CURLOPT_PROXY header to the given value.
- */
- void useProxy(const std::string& proxy);
-
- /**
- * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
- */
- void allowCookies();
-
- /*virtual*/ bool isValid() ;
-
-public:
- /**
- * @brief Give this pipe a chance to handle a generated error
- */
- virtual EStatus handleError(EStatus status, LLPumpIO* pump);
-
-
-protected:
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- enum EState
- {
- STATE_INITIALIZED,
- STATE_WAITING_FOR_RESPONSE,
- STATE_PROCESSING_RESPONSE,
- STATE_HAVE_RESPONSE,
- };
- EState mState;
- EHTTPMethod mAction;
- bool mFollowRedirects;
- LLURLRequestDetail* mDetail;
- LLIOPipe::ptr_t mCompletionCallback;
- S32 mRequestTransferedBytes;
- S32 mResponseTransferedBytes;
-
- static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
-
-private:
- /**
- * @brief Initialize the object. Called during construction.
- */
- void initialize();
-
- /**
- * @brief Handle action specific url request configuration.
- *
- * @return Returns true if this is configured.
- */
- bool configure();
-
- /**
- * @brief Download callback method.
- */
- static size_t downCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user);
-
- /**
- * @brief Upload callback method.
- */
- static size_t upCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user);
-
- /**
- * @brief Declaration of unimplemented method to prevent copy
- * construction.
- */
- LLURLRequest(const LLURLRequest&);
-};
-
-
-/**
- * @class LLContextURLExtractor
- * @brief This class unpacks the url out of a agent usher service so
- * it can be packed into a LLURLRequest object.
- * @see LLIOPipe
- *
- * This class assumes that the context is a map that contains an entry
- * named CONTEXT_DEST_URI_SD_LABEL.
- */
-class LLContextURLExtractor : public LLIOPipe
-{
-public:
- LLContextURLExtractor(LLURLRequest* req) : mRequest(req) {}
- ~LLContextURLExtractor() {}
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- LLURLRequest* mRequest;
-};
-
-
-/**
- * @class LLURLRequestComplete
- * @brief Class which can optionally be used with an LLURLRequest to
- * get notification when the url request is complete.
- */
-class LLURLRequestComplete : public LLIOPipe
-{
-public:
-
- // Called once for each header received, except status lines
- virtual void header(const std::string& header, const std::string& value);
-
- // May be called more than once, particularly for redirects and proxy madness.
- // Ex. a 200 for a connection to https through a proxy, followed by the "real" status
- // a 3xx for a redirect followed by a "real" status, or more redirects.
- virtual void httpStatus(S32 status, const std::string& reason) { }
-
- virtual void complete(
- const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer);
-
- /**
- * @brief This method is called when we got a valid response.
- *
- * It is up to class implementers to do something useful here.
- */
- virtual void response(
- const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer);
-
- /**
- * @brief This method is called if there was no response.
- *
- * It is up to class implementers to do something useful here.
- */
- virtual void noResponse();
-
- /**
- * @brief This method will be called by the LLURLRequest object.
- *
- * If this is set to STATUS_OK or STATUS_STOP, then the transfer
- * is asssumed to have worked. This will lead to calling response()
- * on the next call to process(). Otherwise, this object will call
- * noResponse() on the next call to process.
- * @param status The status of the URLRequest.
- */
- void responseStatus(EStatus status);
-
- // constructor & destructor.
- LLURLRequestComplete();
- virtual ~LLURLRequestComplete();
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
- // value to note if we actually got the response. This value
- // depends on correct usage from the LLURLRequest instance.
- EStatus mRequestStatus;
-};
-
-#endif // LL_LLURLREQUEST_H
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 10dbbef046..2f4b47286d 100755
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -50,7 +50,6 @@
#include "lldir.h"
#include "llerror.h"
#include "llfasttimer.h"
-#include "llhttpclient.h"
#include "llhttpnodeadapter.h"
#include "llmd5.h"
#include "llmessagebuilder.h"
@@ -4024,7 +4023,7 @@ void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::st
postData["message"] = message;
postData["body"] = body;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index fc391da633..133db620e6 100755
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -50,7 +50,6 @@
#include "lltimer.h"
#include "llpacketring.h"
#include "llhost.h"
-#include "llcurl.h"
#include "llhttpnode.h"
//#include "llpacketack.h"
#include "llsingleton.h"
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 52626b0302..4bfd0de81e 100755
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -146,6 +146,8 @@ void LLPluginClassMedia::reset()
mClickTarget.clear();
mClickUUID.clear();
mStatusCode = 0;
+
+ mClickEnforceTarget = false;
// media_time class
mCurrentTime = 0.0f;
@@ -1358,6 +1360,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
sendMessage(message);
}
+void LLPluginClassMedia::setOverrideClickTarget(const std::string &target)
+{
+ mClickEnforceTarget = true;
+ mOverrideClickTarget = target;
+}
+
void LLPluginClassMedia::crashPlugin()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 5fe8254331..96d577f43c 100755
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -249,6 +249,13 @@ public:
// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
std::string getClickUUID() const { return mClickUUID; };
+ // mClickTarget is received from message and governs how link will be opened
+ // use this to enforce your own way of opening links inside plugins
+ void setOverrideClickTarget(const std::string &target);
+ void resetOverrideClickTarget() { mClickEnforceTarget = false; };
+ bool isOverrideClickTarget() const { return mClickEnforceTarget; }
+ std::string getOverrideClickTarget() const { return mOverrideClickTarget; };
+
// These are valid during MEDIA_EVENT_DEBUG_MESSAGE
std::string getDebugMessageText() const { return mDebugMessageText; };
std::string getDebugMessageLevel() const { return mDebugMessageLevel; };
@@ -404,6 +411,8 @@ protected:
std::string mClickNavType;
std::string mClickTarget;
std::string mClickUUID;
+ bool mClickEnforceTarget;
+ std::string mOverrideClickTarget;
std::string mDebugMessageText;
std::string mDebugMessageLevel;
S32 mGeometryX;
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 3f258ee383..dd2e806dda 100755
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -9,6 +9,7 @@ include(LLMessage)
include(LLCoreHttp)
include(LLXML)
include(LLPhysicsExtensions)
+include(LLCharacter)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
@@ -17,6 +18,7 @@ include_directories(
${LLXML_INCLUDE_DIRS}
${LIBS_PREBUILT_DIR}/include/collada
${LIBS_PREBUILT_DIR}/include/collada/1.4
+ ${LLCHARACTER_INCLUDE_DIRS}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -25,11 +27,13 @@ include_directories(SYSTEM
)
set(llprimitive_SOURCE_FILES
+ lldaeloader.cpp
llmaterialid.cpp
llmaterial.cpp
llmaterialtable.cpp
llmediaentry.cpp
llmodel.cpp
+ llmodelloader.cpp
llprimitive.cpp
llprimtexturelist.cpp
lltextureanim.cpp
@@ -41,16 +45,17 @@ set(llprimitive_SOURCE_FILES
set(llprimitive_HEADER_FILES
CMakeLists.txt
-
+ lldaeloader.h
legacy_object_types.h
- lllslconstants.h
llmaterial.h
llmaterialid.h
llmaterialtable.h
llmediaentry.h
llmodel.h
+ llmodelloader.h
llprimitive.h
llprimtexturelist.h
+ lllslconstants.h
lltextureanim.h
lltextureentry.h
lltreeparams.h
@@ -74,6 +79,7 @@ target_link_libraries(llprimitive
${LLCOREHTTP_LIBRARIES}
${LLXML_LIBRARIES}
${LLPHYSICSEXTENSIONS_LIBRARIES}
+ ${LLCHARACTER_LIBRARIES}
${BOOST_COROUTINE_LIBRARY}
${BOOST_CONTEXT_LIBRARY}
)
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
new file mode 100644
index 0000000000..c1b74b1fd7
--- /dev/null
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -0,0 +1,2436 @@
+/**
+ * @file lldaeloader.cpp
+ * @brief LLDAELoader class implementation
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#if LL_MSVC
+#pragma warning (disable : 4263)
+#pragma warning (disable : 4264)
+#endif
+#include "dae.h"
+#include "dom/domAsset.h"
+#include "dom/domBind_material.h"
+#include "dom/domCOLLADA.h"
+#include "dom/domConstants.h"
+#include "dom/domController.h"
+#include "dom/domEffect.h"
+#include "dom/domGeometry.h"
+#include "dom/domInstance_geometry.h"
+#include "dom/domInstance_material.h"
+#include "dom/domInstance_node.h"
+#include "dom/domInstance_effect.h"
+#include "dom/domMaterial.h"
+#include "dom/domMatrix.h"
+#include "dom/domNode.h"
+#include "dom/domProfile_COMMON.h"
+#include "dom/domRotate.h"
+#include "dom/domScale.h"
+#include "dom/domTranslate.h"
+#include "dom/domVisual_scene.h"
+#if LL_MSVC
+#pragma warning (default : 4263)
+#pragma warning (default : 4264)
+#endif
+
+#include <boost/lexical_cast.hpp>
+
+#include "lldaeloader.h"
+#include "llsdserialize.h"
+#include "lljoint.h"
+
+#include "glh/glh_linear.h"
+#include "llmatrix4a.h"
+
+std::string colladaVersion[VERSIONTYPE_COUNT+1] =
+{
+ "1.4.0",
+ "1.4.1",
+ "Unsupported"
+};
+
+static const std::string lod_suffix[LLModel::NUM_LODS] =
+{
+ "_LOD0",
+ "_LOD1",
+ "_LOD2",
+ "",
+ "_PHYS",
+};
+
+const U32 LIMIT_MATERIALS_OUTPUT = 12;
+
+bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
+ domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
+{
+ idx_stride = 0;
+
+ for (U32 j = 0; j < inputs.getCount(); ++j)
+ {
+ idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride);
+
+ if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
+ { //found vertex array
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ domVertices* vertices = (domVertices*) elem.cast();
+ if ( !vertices )
+ {
+ return false;
+ }
+
+ domInputLocal_Array& v_inp = vertices->getInput_array();
+
+
+ for (U32 k = 0; k < v_inp.getCount(); ++k)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
+ {
+ pos_offset = inputs[j]->getOffset();
+
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ pos_source = (domSource*) elem.cast();
+ }
+
+ if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0)
+ {
+ norm_offset = inputs[j]->getOffset();
+
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ norm_source = (domSource*) elem.cast();
+ }
+ }
+ }
+
+ if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
+ {
+ //found normal array for this triangle list
+ norm_offset = inputs[j]->getOffset();
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ norm_source = (domSource*) elem.cast();
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
+ { //found texCoords
+ tc_offset = inputs[j]->getOffset();
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ tc_source = (domSource*) elem.cast();
+ }
+ }
+
+ idx_stride += 1;
+
+ return true;
+}
+
+LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
+{
+ LLVolumeFace face;
+ std::vector<LLVolumeFace::VertexData> verts;
+ std::vector<U16> indices;
+
+ const domInputLocalOffset_Array& inputs = tri->getInput_array();
+
+ S32 pos_offset = -1;
+ S32 tc_offset = -1;
+ S32 norm_offset = -1;
+
+ domSource* pos_source = NULL;
+ domSource* tc_source = NULL;
+ domSource* norm_source = NULL;
+
+ S32 idx_stride = 0;
+
+ if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+
+ if (!pos_source || !pos_source->getFloat_array())
+ {
+ LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
+ domPRef p = tri->getP();
+ domListOfUInts& idx = p->getValue();
+
+ domListOfFloats dummy ;
+ domListOfFloats& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy ;
+
+ if (pos_source)
+ {
+ if(v.getCount() == 0)
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+
+ face.mExtents[0].set(v[0], v[1], v[2]);
+ face.mExtents[1].set(v[0], v[1], v[2]);
+ }
+
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ for (U32 i = 0; i < idx.getCount(); i += idx_stride)
+ {
+ LLVolumeFace::VertexData cv;
+ if (pos_source)
+ {
+ cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0],
+ v[idx[i+pos_offset]*3+1],
+ v[idx[i+pos_offset]*3+2]));
+ }
+
+ if (tc_source)
+ {
+ cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
+ tc[idx[i+tc_offset]*2+1]);
+ }
+
+ if (norm_source)
+ {
+ cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
+ n[idx[i+norm_offset]*3+1],
+ n[idx[i+norm_offset]*3+2]));
+ }
+
+ BOOL found = FALSE;
+
+ LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
+ point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+
+ if (point_iter != point_map.end())
+ {
+ for (U32 j = 0; j < point_iter->second.size(); ++j)
+ {
+ // We have a matching loc
+ //
+ if ((point_iter->second)[j] == cv)
+ {
+ U16 shared_index = (point_iter->second)[j].mIndex;
+
+ // Don't share verts within the same tri, degenerate
+ //
+ if ((indices.size() % 3) && (indices[indices.size()-1] != shared_index))
+ {
+ found = true;
+ indices.push_back(shared_index);
+ }
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
+ verts.push_back(cv);
+ if (verts.size() >= 65535)
+ {
+ //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
+ return LLModel::VERTEX_NUMBER_OVERFLOW ;
+ }
+ U16 index = (U16) (verts.size()-1);
+ indices.push_back(index);
+
+ LLVolumeFace::VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+ }
+ }
+
+ if (indices.size()%3 == 0 && verts.size() >= 65532)
+ {
+ std::string material;
+
+ if (tri->getMaterial())
+ {
+ material = std::string(tri->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ //ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ //ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
+ face = LLVolumeFace();
+ point_map.clear();
+ }
+ }
+
+ if (!verts.empty())
+ {
+ std::string material;
+
+ if (tri->getMaterial())
+ {
+ material = std::string(tri->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ //ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ //ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly)
+{
+ domPRef p = poly->getP();
+ domListOfUInts& idx = p->getValue();
+
+ if (idx.getCount() == 0)
+ {
+ return LLModel::NO_ERRORS ;
+ }
+
+ const domInputLocalOffset_Array& inputs = poly->getInput_array();
+
+
+ domListOfUInts& vcount = poly->getVcount()->getValue();
+
+ S32 pos_offset = -1;
+ S32 tc_offset = -1;
+ S32 norm_offset = -1;
+
+ domSource* pos_source = NULL;
+ domSource* tc_source = NULL;
+ domSource* norm_source = NULL;
+
+ S32 idx_stride = 0;
+
+ if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+
+ LLVolumeFace face;
+
+ std::vector<U16> indices;
+ std::vector<LLVolumeFace::VertexData> verts;
+
+ domListOfFloats v;
+ domListOfFloats tc;
+ domListOfFloats n;
+
+ if (pos_source)
+ {
+ v = pos_source->getFloat_array()->getValue();
+ face.mExtents[0].set(v[0], v[1], v[2]);
+ face.mExtents[1].set(v[0], v[1], v[2]);
+ }
+
+ if (tc_source)
+ {
+ tc = tc_source->getFloat_array()->getValue();
+ }
+
+ if (norm_source)
+ {
+ n = norm_source->getFloat_array()->getValue();
+ }
+
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ U32 cur_idx = 0;
+ for (U32 i = 0; i < vcount.getCount(); ++i)
+ { //for each polygon
+ U32 first_index = 0;
+ U32 last_index = 0;
+ for (U32 j = 0; j < vcount[i]; ++j)
+ { //for each vertex
+
+ LLVolumeFace::VertexData cv;
+
+ if (pos_source)
+ {
+ cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0],
+ v[idx[cur_idx+pos_offset]*3+1],
+ v[idx[cur_idx+pos_offset]*3+2]);
+ if (!cv.getPosition().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+ }
+
+ if (tc_source)
+ {
+ cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
+ tc[idx[cur_idx+tc_offset]*2+1]);
+ }
+
+ if (norm_source)
+ {
+ cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0],
+ n[idx[cur_idx+norm_offset]*3+1],
+ n[idx[cur_idx+norm_offset]*3+2]);
+
+ if (!cv.getNormal().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+ }
+
+ cur_idx += idx_stride;
+
+ BOOL found = FALSE;
+
+ LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
+ LLVector3 pos3(cv.getPosition().getF32ptr());
+ point_iter = point_map.find(pos3);
+
+ if (point_iter != point_map.end())
+ {
+ for (U32 k = 0; k < point_iter->second.size(); ++k)
+ {
+ if ((point_iter->second)[k] == cv)
+ {
+ found = TRUE;
+ U32 index = (point_iter->second)[k].mIndex;
+ if (j == 0)
+ {
+ first_index = index;
+ }
+ else if (j == 1)
+ {
+ last_index = index;
+ }
+ else
+ {
+ // if these are the same, we have a very, very skinny triangle (coincident verts on one or more edges)
+ //
+ llassert((first_index != last_index) && (last_index != index) && (first_index != index));
+ indices.push_back(first_index);
+ indices.push_back(last_index);
+ indices.push_back(index);
+ last_index = index;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
+ verts.push_back(cv);
+ if (verts.size() >= 65535)
+ {
+ //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
+ return LLModel::VERTEX_NUMBER_OVERFLOW ;
+ }
+ U16 index = (U16) (verts.size()-1);
+
+ if (j == 0)
+ {
+ first_index = index;
+ }
+ else if (j == 1)
+ {
+ last_index = index;
+ }
+ else
+ {
+ // detect very skinny degenerate triangles with collapsed edges
+ //
+ llassert((first_index != last_index) && (last_index != index) && (first_index != index));
+ indices.push_back(first_index);
+ indices.push_back(last_index);
+ indices.push_back(index);
+ last_index = index;
+ }
+
+ LLVolumeFace::VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[pos3].push_back(d);
+ }
+ }
+
+ if (indices.size()%3 == 0 && indices.size() >= 65532)
+ {
+ std::string material;
+
+ if (poly->getMaterial())
+ {
+ material = std::string(poly->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ //ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ //ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
+ face = LLVolumeFace();
+ verts.clear();
+ indices.clear();
+ point_map.clear();
+ }
+ }
+ }
+
+ if (!verts.empty())
+ {
+ std::string material;
+
+ if (poly->getMaterial())
+ {
+ material = std::string(poly->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ //ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ //ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolygonsRef& poly)
+{
+ LLVolumeFace face;
+ std::vector<U16> indices;
+ std::vector<LLVolumeFace::VertexData> verts;
+
+ const domInputLocalOffset_Array& inputs = poly->getInput_array();
+
+ S32 v_offset = -1;
+ S32 n_offset = -1;
+ S32 t_offset = -1;
+
+ domListOfFloats* v = NULL;
+ domListOfFloats* n = NULL;
+ domListOfFloats* t = NULL;
+
+ U32 stride = 0;
+ for (U32 i = 0; i < inputs.getCount(); ++i)
+ {
+ stride = llmax((U32) inputs[i]->getOffset()+1, stride);
+
+ if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0)
+ { //found vertex array
+ v_offset = inputs[i]->getOffset();
+
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domVertices* vertices = (domVertices*) elem.cast();
+ if (!vertices)
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+ domInputLocal_Array& v_inp = vertices->getInput_array();
+
+ for (U32 k = 0; k < v_inp.getCount(); ++k)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
+ {
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ if (!src)
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+ v = &(src->getFloat_array()->getValue());
+ }
+ }
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0)
+ {
+ n_offset = inputs[i]->getOffset();
+ //found normal array for this triangle list
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ if (!src)
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+ n = &(src->getFloat_array()->getValue());
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0)
+ { //found texCoords
+ t_offset = inputs[i]->getOffset();
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ if (!src)
+ {
+ return LLModel::BAD_ELEMENT;
+ }
+ t = &(src->getFloat_array()->getValue());
+ }
+ }
+
+ domP_Array& ps = poly->getP_array();
+
+ //make a triangle list in <verts>
+ for (U32 i = 0; i < ps.getCount(); ++i)
+ { //for each polygon
+ domListOfUInts& idx = ps[i]->getValue();
+ for (U32 j = 0; j < idx.getCount()/stride; ++j)
+ { //for each vertex
+ if (j > 2)
+ {
+ U32 size = verts.size();
+ LLVolumeFace::VertexData v0 = verts[size-3];
+ LLVolumeFace::VertexData v1 = verts[size-1];
+
+ verts.push_back(v0);
+ verts.push_back(v1);
+ }
+
+ LLVolumeFace::VertexData vert;
+
+
+ if (v)
+ {
+ U32 v_idx = idx[j*stride+v_offset]*3;
+ v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount());
+ vert.getPosition().set(v->get(v_idx),
+ v->get(v_idx+1),
+ v->get(v_idx+2));
+ }
+
+ //bounds check n and t lookups because some FBX to DAE converters
+ //use negative indices and empty arrays to indicate data does not exist
+ //for a particular channel
+ if (n && n->getCount() > 0)
+ {
+ U32 n_idx = idx[j*stride+n_offset]*3;
+ n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount());
+ vert.getNormal().set(n->get(n_idx),
+ n->get(n_idx+1),
+ n->get(n_idx+2));
+ }
+ else
+ {
+ vert.getNormal().clear();
+ }
+
+
+ if (t && t->getCount() > 0)
+ {
+ U32 t_idx = idx[j*stride+t_offset]*2;
+ t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount());
+ vert.mTexCoord.setVec(t->get(t_idx),
+ t->get(t_idx+1));
+ }
+ else
+ {
+ vert.mTexCoord.clear();
+ }
+
+
+ verts.push_back(vert);
+ }
+ }
+
+ if (verts.empty())
+ {
+ return LLModel::NO_ERRORS;
+ }
+
+ face.mExtents[0] = verts[0].getPosition();
+ face.mExtents[1] = verts[0].getPosition();
+
+ //create a map of unique vertices to indices
+ std::map<LLVolumeFace::VertexData, U32> vert_idx;
+
+ U32 cur_idx = 0;
+ for (U32 i = 0; i < verts.size(); ++i)
+ {
+ std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.find(verts[i]);
+ if (iter == vert_idx.end())
+ {
+ vert_idx[verts[i]] = cur_idx++;
+ }
+ }
+
+ //build vertex array from map
+ std::vector<LLVolumeFace::VertexData> new_verts;
+ new_verts.resize(vert_idx.size());
+
+ for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter)
+ {
+ new_verts[iter->second] = iter->first;
+ update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition());
+ }
+
+ //build index array from map
+ indices.resize(verts.size());
+
+ for (U32 i = 0; i < verts.size(); ++i)
+ {
+ indices[i] = vert_idx[verts[i]];
+ llassert(!i || (indices[i-1] != indices[i]));
+ }
+
+ // DEBUG just build an expanded triangle list
+ /*for (U32 i = 0; i < verts.size(); ++i)
+ {
+ indices.push_back((U16) i);
+ update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition());
+ }*/
+
+ if (!new_verts.empty())
+ {
+ std::string material;
+
+ if (poly->getMaterial())
+ {
+ material = std::string(poly->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(new_verts, indices);
+
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!n)
+ {
+ //ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!t)
+ {
+ //ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+//-----------------------------------------------------------------------------
+// LLDAELoader
+//-----------------------------------------------------------------------------
+LLDAELoader::LLDAELoader(
+ std::string filename,
+ S32 lod,
+ load_callback_t load_cb,
+ joint_lookup_func_t joint_lookup_func,
+ texture_load_func_t texture_load_func,
+ state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointMap,
+ JointSet& jointsFromNodes,
+ U32 modelLimit)
+: LLModelLoader(
+ filename,
+ lod,
+ load_cb,
+ joint_lookup_func,
+ texture_load_func,
+ state_cb,
+ opaque_userdata,
+ jointMap,
+ jointsFromNodes),
+mGeneratedModelLimit(modelLimit)
+{
+}
+
+LLDAELoader::~LLDAELoader()
+{
+}
+
+struct ModelSort
+{
+ bool operator()(const LLPointer< LLModel >& lhs, const LLPointer< LLModel >& rhs)
+ {
+ if (lhs->mSubmodelID < rhs->mSubmodelID)
+ {
+ return true;
+ }
+ return LLStringUtil::compareInsensitive(lhs->mLabel, rhs->mLabel) < 0;
+ }
+};
+
+bool LLDAELoader::OpenFile(const std::string& filename)
+{
+ //no suitable slm exists, load from the .dae file
+ DAE dae;
+ domCOLLADA* dom = dae.open(filename);
+
+ if (!dom)
+ {
+ LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ return false;
+ }
+ //Dom version
+ daeString domVersion = dae.getDomVersion();
+ std::string sldom(domVersion);
+ LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL;
+ //Dae version
+ domVersionType docVersion = dom->getVersion();
+ //0=1.4
+ //1=1.4.1
+ //2=Currently unsupported, however may work
+ if (docVersion > 1 )
+ {
+ docVersion = VERSIONTYPE_COUNT;
+ }
+ LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL;
+
+
+ daeDatabase* db = dae.getDatabase();
+
+ daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
+
+ daeDocument* doc = dae.getDoc(mFilename);
+ if (!doc)
+ {
+ LL_WARNS() << "can't find internal doc" << LL_ENDL;
+ return false;
+ }
+
+ daeElement* root = doc->getDomRoot();
+ if (!root)
+ {
+ LL_WARNS() << "document has no root" << LL_ENDL;
+ return false;
+ }
+
+ //Verify some basic properties of the dae
+ //1. Basic validity check on controller
+ U32 controllerCount = (int) db->getElementCount( NULL, "controller" );
+ bool result = false;
+ for ( int i=0; i<controllerCount; ++i )
+ {
+ domController* pController = NULL;
+ db->getElement( (daeElement**) &pController, i , NULL, "controller" );
+ result = verifyController( pController );
+ if (!result)
+ {
+ LL_INFOS() << "Could not verify controller" << LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ return true;
+ }
+ }
+
+
+ //get unit scale
+ mTransform.setIdentity();
+
+ domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
+
+ if (unit)
+ {
+ F32 meter = unit->getMeter();
+ mTransform.mMatrix[0][0] = meter;
+ mTransform.mMatrix[1][1] = meter;
+ mTransform.mMatrix[2][2] = meter;
+ }
+
+ //get up axis rotation
+ LLMatrix4 rotation;
+
+ domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP
+ domAsset::domUp_axis* up_axis =
+ daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
+
+ if (up_axis)
+ {
+ up = up_axis->getValue();
+ }
+
+ if (up == UPAXISTYPE_X_UP)
+ {
+ rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
+ }
+ else if (up == UPAXISTYPE_Y_UP)
+ {
+ rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
+ }
+
+ rotation *= mTransform;
+ mTransform = rotation;
+
+ mTransform.condition();
+
+ U32 submodel_limit = count > 0 ? mGeneratedModelLimit/count : 0;
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //build map of domEntities to LLModel
+ domMesh* mesh = NULL;
+ db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
+
+ if (mesh)
+ {
+
+ std::vector<LLModel*> models;
+
+ loadModelsFromDomMesh(mesh, models, submodel_limit);
+
+ std::vector<LLModel*>::iterator i;
+ i = models.begin();
+ while (i != models.end())
+ {
+ LLModel* mdl = *i;
+ if(mdl->getStatus() != LLModel::NO_ERRORS)
+ {
+ setLoadState(ERROR_MODEL + mdl->getStatus()) ;
+ return false; //abort
+ }
+
+ if (mdl && validate_model(mdl))
+ {
+ mModelList.push_back(mdl);
+ mModelsMap[mesh].push_back(mdl);
+ }
+ i++;
+ }
+ }
+ }
+
+ std::sort(mModelList.begin(), mModelList.end(), ModelSort());
+
+ model_list::iterator model_iter = mModelList.begin();
+ while (model_iter != mModelList.end())
+ {
+ LLModel* mdl = *model_iter;
+ U32 material_count = mdl->mMaterialList.size();
+ LL_INFOS() << "Importing " << mdl->mLabel << " model with " << material_count << " material references" << LL_ENDL;
+ std::vector<std::string>::iterator mat_iter = mdl->mMaterialList.begin();
+ std::vector<std::string>::iterator end_iter = material_count > LIMIT_MATERIALS_OUTPUT
+ ? mat_iter + LIMIT_MATERIALS_OUTPUT
+ : mdl->mMaterialList.end();
+ while (mat_iter != end_iter)
+ {
+ LL_INFOS() << mdl->mLabel << " references " << (*mat_iter) << LL_ENDL;
+ mat_iter++;
+ }
+ model_iter++;
+ }
+
+ count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //add skinned meshes as instances
+ domSkin* skin = NULL;
+ db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
+
+ if (skin)
+ {
+ domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
+
+ if (geom)
+ {
+ domMesh* mesh = geom->getMesh();
+ if (mesh)
+ {
+ std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
+ while (i != mModelsMap[mesh].end())
+ {
+ LLPointer<LLModel> mdl = *i;
+ LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin);
+ i++;
+ }
+ }
+ }
+ }
+ }
+
+ LL_INFOS()<< "Collada skins processed: " << count <<LL_ENDL;
+
+ daeElement* scene = root->getDescendant("visual_scene");
+
+ if (!scene)
+ {
+ LL_WARNS() << "document has no visual_scene" << LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ return true;
+ }
+
+ setLoadState( DONE );
+
+ bool badElement = false;
+
+ processElement( scene, badElement, &dae );
+
+ if ( badElement )
+ {
+ LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ }
+
+ return true;
+}
+
+void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, domMesh* mesh, domSkin* skin)
+{
+ llassert(model && dae && mesh && skin);
+
+ if (model)
+ {
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 normalized_transformation;
+ normalized_transformation.setTranslation(mesh_translation_vector);
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= normalized_transformation;
+ normalized_transformation = mesh_scale;
+
+ glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
+ inv_mat = inv_mat.inverse();
+ LLMatrix4 inverse_normalized_transformation(inv_mat.m);
+
+ domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
+
+ if (bind_mat)
+ { //get bind shape matrix
+ domFloat4x4& dom_value = bind_mat->getValue();
+
+ LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ LLMatrix4 trans = normalized_transformation;
+ trans *= skin_info.mBindShapeMatrix;
+ skin_info.mBindShapeMatrix = trans;
+ }
+
+
+ //Some collada setup for accessing the skeleton
+ daeElement* pElement = 0;
+ dae->getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
+
+ //Try to get at the skeletal instance controller
+ domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
+ bool missingSkeletonOrScene = false;
+
+ //If no skeleton, do a breadth-first search to get at specific joints
+ bool rootNode = false;
+
+ //Need to test for a skeleton that does not have a root node
+ //This occurs when your instance controller does not have an associated scene
+ if ( pSkeleton )
+ {
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ rootNode = true;
+ }
+
+ }
+ if ( !pSkeleton || !rootNode )
+ {
+ daeElement* pScene = root->getDescendant("visual_scene");
+ if ( !pScene )
+ {
+ LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL;
+ missingSkeletonOrScene = true;
+ }
+ else
+ {
+ //Get the children at this level
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+
+ //Process any children that are joints
+ //Not all children are joints, some code be ambient lights, cameras, geometry etc..
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ if ( isNodeAJoint( pNode ) )
+ {
+ processJointNode( pNode, mJointList );
+ }
+ }
+ }
+ }
+ else
+ //Has Skeleton
+ {
+ //Get the root node of the skeleton
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ //Once we have the root node - start acccessing it's joint components
+ const int jointCnt = mJointMap.size();
+ JointMap :: const_iterator jointIt = mJointMap.begin();
+
+ //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ //Build a joint for the resolver to work with
+ char str[64]={0};
+ sprintf(str,"./%s",(*jointIt).first.c_str() );
+ //LL_WARNS()<<"Joint "<< str <<LL_ENDL;
+
+ //Setup the resolver
+ daeSIDResolver resolver( pSkeletonRootNode, str );
+
+ //Look for the joint
+ domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
+ if ( pJoint )
+ {
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolverA( pJoint, "./translate" );
+ domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
+ daeSIDResolver jointResolverB( pJoint, "./location" );
+ domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
+
+ LLMatrix4 workingTransform;
+
+ //Translation via SID
+ if ( pTranslateA )
+ {
+ extractTranslation( pTranslateA, workingTransform );
+ }
+ else
+ if ( pTranslateB )
+ {
+ extractTranslation( pTranslateB, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
+ if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
+ missingSkeletonOrScene = true;
+ }
+ else
+ if ( pTranslateElement )
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ else
+ {
+ extractTranslationViaSID( pJoint, workingTransform );
+ }
+
+ }
+
+ //Store the joint transform w/respect to it's name.
+ mJointList[(*jointIt).second.c_str()] = workingTransform;
+ }
+ }
+
+ //If anything failed in regards to extracting the skeleton, joints or translation id,
+ //mention it
+ if ( missingSkeletonOrScene )
+ {
+ LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL;
+ }
+ }//got skeleton?
+ }
+
+
+ domSkin::domJoints* joints = skin->getJoints();
+
+ domInputLocal_Array& joint_input = joints->getInput_array();
+
+ for (size_t i = 0; i < joint_input.getCount(); ++i)
+ {
+ domInputLocal* input = joint_input.get(i);
+ xsNMTOKEN semantic = input->getSemantic();
+
+ if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
+ { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
+ daeElement* elem = input->getSource().getElement();
+
+ domSource* source = daeSafeCast<domSource>(elem);
+ if (source)
+ {
+
+
+ domName_array* names_source = source->getName_array();
+
+ if (names_source)
+ {
+ domListOfNames &names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j));
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ else
+ {
+ domIDREF_array* names_source = source->getIDREF_array();
+ if (names_source)
+ {
+ xsIDREFS& names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j).getID());
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ }
+ }
+ }
+ else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
+ { //found inv_bind_matrix array, fill model->mInvBindMatrix
+ domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
+ if (source)
+ {
+ domFloat_array* t = source->getFloat_array();
+ if (t)
+ {
+ domListOfFloats& transform = t->getValue();
+ S32 count = transform.getCount()/16;
+
+ for (S32 k = 0; k < count; ++k)
+ {
+ LLMatrix4 mat;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ mat.mMatrix[i][j] = transform[k*16 + i + j*4];
+ }
+ }
+
+ model->mSkinInfo.mInvBindMatrix.push_back(mat);
+ }
+ }
+ }
+ }
+ }
+
+ //Now that we've parsed the joint array, let's determine if we have a full rig
+ //(which means we have all the joint sthat are required for an avatar versus
+ //a skinned asset attached to a node in a file that contains an entire skeleton,
+ //but does not use the skeleton).
+ buildJointToNodeMappingFromScene( root );
+ critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames );
+
+ if ( !missingSkeletonOrScene )
+ {
+ //Set the joint translations on the avatar - if it's a full mapping
+ //The joints are reset in the dtor
+ if ( getRigWithSceneParity() )
+ {
+ JointMap :: const_iterator masterJointIt = mJointMap.begin();
+ JointMap :: const_iterator masterJointItEnd = mJointMap.end();
+ for (;masterJointIt!=masterJointItEnd;++masterJointIt )
+ {
+ std::string lookingForJoint = (*masterJointIt).first.c_str();
+
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLJoint* pJoint = mJointLookupFunc(lookingForJoint,mOpaqueData);
+ if ( pJoint )
+ {
+ LLUUID fake_mesh_id;
+ fake_mesh_id.generate();
+ pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, "");
+ }
+ else
+ {
+ //Most likely an error in the asset.
+ LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
+ }
+ }
+ }
+ }
+ } //missingSkeletonOrScene
+
+ //We need to construct the alternate bind matrix (which contains the new joint positions)
+ //in the same order as they were stored in the joint buffer. The joints associated
+ //with the skeleton are not stored in the same order as they are in the exported joint buffer.
+ //This remaps the skeletal joints to be in the same order as the joints stored in the model.
+ std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
+ const int jointCnt = model->mSkinInfo.mJointNames.size();
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ std::string lookingForJoint = (*jointIt).c_str();
+ //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
+ //and store it in the alternate bind matrix
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
+ newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
+ model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
+ }
+ else
+ {
+ LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL;
+ }
+ }
+
+ //grab raw position array
+
+ domVertices* verts = mesh->getVertices();
+ if (verts)
+ {
+ domInputLocal_Array& inputs = verts->getInput_array();
+ for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
+ {
+ domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (pos_source)
+ {
+ domFloat_array* pos_array = pos_source->getFloat_array();
+ if (pos_array)
+ {
+ domListOfFloats& pos = pos_array->getValue();
+
+ for (size_t j = 0; j < pos.getCount(); j += 3)
+ {
+ if (pos.getCount() <= j+2)
+ {
+ LL_ERRS() << "Invalid position array size." << LL_ENDL;
+ }
+
+ LLVector3 v(pos[j], pos[j+1], pos[j+2]);
+
+ //transform from COLLADA space to volume space
+ v = v * inverse_normalized_transformation;
+
+ model->mPosition.push_back(v);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //grab skin weights array
+ domSkin::domVertex_weights* weights = skin->getVertex_weights();
+ if (weights)
+ {
+ domInputLocalOffset_Array& inputs = weights->getInput_array();
+ domFloat_array* vertex_weights = NULL;
+ for (size_t i = 0; i < inputs.getCount(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
+ {
+ domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (weight_source)
+ {
+ vertex_weights = weight_source->getFloat_array();
+ }
+ }
+ }
+
+ if (vertex_weights)
+ {
+ domListOfFloats& w = vertex_weights->getValue();
+ domListOfUInts& vcount = weights->getVcount()->getValue();
+ domListOfInts& v = weights->getV()->getValue();
+
+ U32 c_idx = 0;
+ for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
+ { //for each vertex
+ daeUInt count = vcount[vc_idx];
+
+ //create list of weights that influence this vertex
+ LLModel::weight_list weight_list;
+
+ for (daeUInt i = 0; i < count; ++i)
+ { //for each weight
+ daeInt joint_idx = v[c_idx++];
+ daeInt weight_idx = v[c_idx++];
+
+ if (joint_idx == -1)
+ {
+ //ignore bindings to bind_shape_matrix
+ continue;
+ }
+
+ F32 weight_value = w[weight_idx];
+
+ weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
+ }
+
+ //sort by joint weight
+ std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
+
+ std::vector<LLModel::JointWeight> wght;
+
+ F32 total = 0.f;
+
+ for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
+ { //take up to 4 most significant weights
+ if (weight_list[i].mWeight > 0.f)
+ {
+ wght.push_back( weight_list[i] );
+ total += weight_list[i].mWeight;
+ }
+ }
+
+ F32 scale = 1.f/total;
+ if (scale != 1.f)
+ { //normalize weights
+ for (U32 i = 0; i < wght.size(); ++i)
+ {
+ wght[i].mWeight *= scale;
+ }
+ }
+
+ model->mSkinWeights[model->mPosition[vc_idx]] = wght;
+ }
+ }
+
+ }
+
+ //add instance to scene for this model
+
+ LLMatrix4 transformation;
+ transformation.initScale(mesh_scale_vector);
+ transformation.setTranslation(mesh_translation_vector);
+ transformation *= mTransform;
+
+ std::map<std::string, LLImportMaterial> materials;
+ for (U32 i = 0; i < model->mMaterialList.size(); ++i)
+ {
+ materials[model->mMaterialList[i]] = LLImportMaterial();
+ }
+ mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// buildJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLDAELoader::buildJointToNodeMappingFromScene( daeElement* pRoot )
+{
+ daeElement* pScene = pRoot->getDescendant("visual_scene");
+ if ( pScene )
+ {
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ processJointToNodeMapping( pNode );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// processJointToNodeMapping()
+//-----------------------------------------------------------------------------
+void LLDAELoader::processJointToNodeMapping( domNode* pNode )
+{
+ if ( isNodeAJoint( pNode ) )
+ {
+ //1.Store the parent
+ std::string nodeName = pNode->getName();
+ if ( !nodeName.empty() )
+ {
+ mJointsFromNode.push_front( pNode->getName() );
+ }
+ //2. Handle the kiddo's
+ processChildJoints( pNode );
+ }
+ else
+ {
+ //Determine if the're any children wrt to this failed node.
+ //This occurs when an armature is exported and ends up being what essentially amounts to
+ //as the root for the visual_scene
+ if ( pNode )
+ {
+ processChildJoints( pNode );
+ }
+ else
+ {
+ LL_INFOS()<<"Node is NULL"<<LL_ENDL;
+ }
+
+ }
+}
+//-----------------------------------------------------------------------------
+// processChildJoint()
+//-----------------------------------------------------------------------------
+void LLDAELoader::processChildJoints( domNode* pParentNode )
+{
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointToNodeMapping( pChildNode );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// isNodeAJoint()
+//-----------------------------------------------------------------------------
+bool LLDAELoader::isNodeAJoint( domNode* pNode )
+{
+ if ( !pNode )
+ {
+ LL_INFOS()<<"Created node is NULL"<<LL_ENDL;
+ return false;
+ }
+
+ return LLModelLoader::isNodeAJoint(pNode->getName());
+}
+//-----------------------------------------------------------------------------
+// verifyCount
+//-----------------------------------------------------------------------------
+bool LLDAELoader::verifyCount( int expected, int result )
+{
+ if ( expected != result )
+ {
+ LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL;
+ return false;
+ }
+ return true;
+}
+//-----------------------------------------------------------------------------
+// verifyController
+//-----------------------------------------------------------------------------
+bool LLDAELoader::verifyController( domController* pController )
+{
+
+ bool result = true;
+
+ domSkin* pSkin = pController->getSkin();
+
+ if ( pSkin )
+ {
+ xsAnyURI & uri = pSkin->getSource();
+ domElement* pElement = uri.getElement();
+
+ if ( !pElement )
+ {
+ LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL;
+ return false;
+ }
+
+ daeString type_str = pElement->getTypeName();
+ if ( stricmp(type_str, "geometry") == 0 )
+ {
+ //Skin is reference directly by geometry and get the vertex count from skin
+ domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights();
+ U32 vertexWeightsCount = pVertexWeights->getCount();
+ domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement();
+ domMesh* pMesh = pGeometry->getMesh();
+
+ if ( pMesh )
+ {
+ //Get vertex count from geometry
+ domVertices* pVertices = pMesh->getVertices();
+ if ( !pVertices )
+ {
+ LL_INFOS()<<"No vertices!"<<LL_ENDL;
+ return false;
+ }
+
+ if ( pVertices )
+ {
+ xsAnyURI src = pVertices->getInput_array()[0]->getSource();
+ domSource* pSource = (domSource*) (domElement*) src.getElement();
+ U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount();
+ result = verifyCount( verticesCount, vertexWeightsCount );
+ if ( !result )
+ {
+ return result;
+ }
+ }
+ }
+
+ U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount();
+ result = verifyCount( vcountCount, vertexWeightsCount );
+ if ( !result )
+ {
+ return result;
+ }
+
+ domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array();
+ U32 sum = 0;
+ for (size_t i=0; i<vcountCount; i++)
+ {
+ sum += pVertexWeights->getVcount()->getValue()[i];
+ }
+ result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() );
+ }
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// extractTranslation()
+//-----------------------------------------------------------------------------
+void LLDAELoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
+{
+ domFloat3 jointTrans = pTranslate->getValue();
+ LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
+ transform.setTranslation( singleJointTranslation );
+}
+//-----------------------------------------------------------------------------
+// extractTranslationViaElement()
+//-----------------------------------------------------------------------------
+void LLDAELoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
+{
+ if ( pTranslateElement )
+ {
+ domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
+ domFloat3 translateChild = pTranslateChild->getValue();
+ LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
+ transform.setTranslation( singleJointTranslation );
+ }
+}
+//-----------------------------------------------------------------------------
+// extractTranslationViaSID()
+//-----------------------------------------------------------------------------
+void LLDAELoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform )
+{
+ if ( pElement )
+ {
+ daeSIDResolver resolver( pElement, "./transform" );
+ domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() );
+ //We are only extracting out the translational component atm
+ LLMatrix4 workingTransform;
+ if ( pMatrix )
+ {
+ domFloat4x4 domArray = pMatrix->getValue();
+ for ( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ workingTransform.mMatrix[i][j] = domArray[i + j*4];
+ }
+ }
+ LLVector3 trans = workingTransform.getTranslation();
+ transform.setTranslation( trans );
+ }
+ }
+ else
+ {
+ LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL;
+ }
+}
+//-----------------------------------------------------------------------------
+// processJointNode()
+//-----------------------------------------------------------------------------
+void LLDAELoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms )
+{
+ if (pNode->getName() == NULL)
+ {
+ LL_WARNS() << "nameless node, can't process" << LL_ENDL;
+ return;
+ }
+
+ //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL;
+
+ //1. handle the incoming node - extract out translation via SID or element
+
+ LLMatrix4 workingTransform;
+
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolverA( pNode, "./translate" );
+ domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
+ daeSIDResolver jointResolverB( pNode, "./location" );
+ domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
+
+ //Translation via SID was successful
+ if ( pTranslateA )
+ {
+ extractTranslation( pTranslateA, workingTransform );
+ }
+ else
+ if ( pTranslateB )
+ {
+ extractTranslation( pTranslateB, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
+ if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
+ daeSIDResolver jointResolver( pNode, "./matrix" );
+ domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
+ if ( pMatrix )
+ {
+ //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
+ domFloat4x4 domArray = pMatrix->getValue();
+ for ( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ workingTransform.mMatrix[i][j] = domArray[i + j*4];
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL;
+ }
+ }
+ else
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ }
+
+ //Store the working transform relative to the nodes name.
+ jointTransforms[ pNode->getName() ] = workingTransform;
+
+ //2. handle the nodes children
+
+ //Gather and handle the incoming nodes children
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointNode( pChildNode, jointTransforms );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// getChildFromElement()
+//-----------------------------------------------------------------------------
+daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string const & name )
+{
+ daeElement* pChildOfElement = pElement->getChild( name.c_str() );
+ if ( pChildOfElement )
+ {
+ return pChildOfElement;
+ }
+ LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
+ return NULL;
+}
+
+void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae )
+{
+ LLMatrix4 saved_transform;
+ bool pushed_mat = false;
+
+ domNode* node = daeSafeCast<domNode>(element);
+ if (node)
+ {
+ pushed_mat = true;
+ saved_transform = mTransform;
+ }
+
+ domTranslate* translate = daeSafeCast<domTranslate>(element);
+ if (translate)
+ {
+ domFloat3 dom_value = translate->getValue();
+
+ LLMatrix4 translation;
+ translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
+
+ translation *= mTransform;
+ mTransform = translation;
+ mTransform.condition();
+ }
+
+ domRotate* rotate = daeSafeCast<domRotate>(element);
+ if (rotate)
+ {
+ domFloat4 dom_value = rotate->getValue();
+
+ LLMatrix4 rotation;
+ rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
+
+ rotation *= mTransform;
+ mTransform = rotation;
+ mTransform.condition();
+ }
+
+ domScale* scale = daeSafeCast<domScale>(element);
+ if (scale)
+ {
+ domFloat3 dom_value = scale->getValue();
+
+
+ LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]);
+ scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes
+ LLMatrix4 scaling;
+ scaling.initScale(scale_vector);
+
+ scaling *= mTransform;
+ mTransform = scaling;
+ mTransform.condition();
+ }
+
+ domMatrix* matrix = daeSafeCast<domMatrix>(element);
+ if (matrix)
+ {
+ domFloat4x4 dom_value = matrix->getValue();
+
+ LLMatrix4 matrix_transform;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ matrix_transform *= mTransform;
+ mTransform = matrix_transform;
+ mTransform.condition();
+ }
+
+ domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
+ if (instance_geo)
+ {
+ domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
+ if (geo)
+ {
+ domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
+ if (mesh)
+ {
+
+ std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
+ while (i != mModelsMap[mesh].end())
+ {
+ LLModel* model = *i;
+
+ LLMatrix4 transformation = mTransform;
+
+ if (mTransform.determinant() < 0)
+ { //negative scales are not supported
+ LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+ badElement = true;
+ }
+
+ LLModelLoader::material_map materials = getMaterials(model, instance_geo, dae);
+
+ // adjust the transformation to compensate for mesh normalization
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ if (transformation.determinant() < 0)
+ { //negative scales are not supported
+ LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+ badElement = true;
+ }
+
+ std::string label;
+
+ if (model->mLabel.empty())
+ {
+ label = getLodlessLabel(instance_geo);
+
+ llassert(!label.empty());
+
+ if (model->mSubmodelID)
+ {
+ label += (char)((int)'a' + model->mSubmodelID);
+ }
+
+ model->mLabel = label + lod_suffix[mLod];
+ }
+ else
+ {
+ // Don't change model's name if possible, it will play havoc with scenes that already use said model.
+ size_t ext_pos = getSuffixPosition(model->mLabel);
+ if (ext_pos != -1)
+ {
+ label = model->mLabel.substr(0, ext_pos);
+ }
+ else
+ {
+ label = model->mLabel;
+ }
+ }
+
+ mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ i++;
+ }
+ }
+ }
+ else
+ {
+ LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
+ badElement = true;
+ }
+
+ }
+
+ domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
+ if (instance_node)
+ {
+ daeElement* instance = instance_node->getUrl().getElement();
+ if (instance)
+ {
+ processElement(instance,badElement, dae);
+ }
+ }
+
+ //process children
+ daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
+ int childCount = children.getCount();
+ for (S32 i = 0; i < childCount; i++)
+ {
+ processElement(children[i],badElement, dae);
+ }
+
+ if (pushed_mat)
+ { //this element was a node, restore transform before processiing siblings
+ mTransform = saved_transform;
+ }
+}
+
+std::map<std::string, LLImportMaterial> LLDAELoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae)
+{
+ std::map<std::string, LLImportMaterial> materials;
+ for (int i = 0; i < model->mMaterialList.size(); i++)
+ {
+ LLImportMaterial import_material;
+
+ domInstance_material* instance_mat = NULL;
+
+ domBind_material::domTechnique_common* technique =
+ daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
+
+ if (technique)
+ {
+ daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
+ for (int j = 0; j < inst_materials.getCount(); j++)
+ {
+ std::string symbol(inst_materials[j]->getSymbol());
+
+ if (symbol == model->mMaterialList[i]) // found the binding
+ {
+ instance_mat = inst_materials[j];
+ break;
+ }
+ }
+ }
+
+ if (instance_mat)
+ {
+ domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
+ if (material)
+ {
+ domInstance_effect* instance_effect =
+ daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
+ if (instance_effect)
+ {
+ domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
+ if (effect)
+ {
+ domProfile_COMMON* profile =
+ daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
+ if (profile)
+ {
+ import_material = profileToMaterial(profile, dae);
+ }
+ }
+ }
+ }
+ }
+
+ import_material.mBinding = model->mMaterialList[i];
+ materials[model->mMaterialList[i]] = import_material;
+ }
+
+ return materials;
+}
+
+LLImportMaterial LLDAELoader::profileToMaterial(domProfile_COMMON* material, DAE* dae)
+{
+ LLImportMaterial mat;
+ mat.mFullbright = FALSE;
+
+ daeElement* diffuse = material->getDescendant("diffuse");
+ if (diffuse)
+ {
+ domCommon_color_or_texture_type_complexType::domTexture* texture =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
+ if (texture)
+ {
+ domCommon_newparam_type_Array newparams = material->getNewparam_array();
+ if (newparams.getCount())
+ {
+
+ for (S32 i = 0; i < newparams.getCount(); i++)
+ {
+ domFx_surface_common* surface = newparams[i]->getSurface();
+ if (surface)
+ {
+ domFx_surface_init_common* init = surface->getFx_surface_init_common();
+ if (init)
+ {
+ domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
+
+ if (init_from.getCount() > i)
+ {
+ domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
+ if (image)
+ {
+ // we only support init_from now - embedded data will come later
+ domImage::domInit_from* init = image->getInit_from();
+ if (init)
+ {
+ mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
+ mat.mDiffuseMapLabel = getElementLabel(material);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (texture->getTexture())
+ {
+ domImage* image = NULL;
+ dae->getDatabase()->getElement((daeElement**) &image, 0, texture->getTexture(), COLLADA_TYPE_IMAGE);
+ if (image)
+ {
+ // we only support init_from now - embedded data will come later
+ domImage::domInit_from* init = image->getInit_from();
+ if (init)
+ {
+ std::string image_path_value = cdom::uriToNativePath(init->getValue().str());
+
+#if LL_WINDOWS
+ // Work-around DOM tendency to resort to UNC names which are only confusing for downstream...
+ //
+ std::string::iterator i = image_path_value.begin();
+ while (*i == '\\')
+ i++;
+ mat.mDiffuseMapFilename.assign(i, image_path_value.end());
+#else
+ mat.mDiffuseMapFilename = image_path_value;
+#endif
+ mat.mDiffuseMapLabel = getElementLabel(material);
+ }
+ }
+ }
+ }
+
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ mat.mDiffuseColor = value;
+ }
+ }
+
+ daeElement* emission = material->getDescendant("emission");
+ if (emission)
+ {
+ LLColor4 emission_color = getDaeColor(emission);
+ if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
+ {
+ mat.mFullbright = TRUE;
+ }
+ }
+
+ return mat;
+}
+
+// try to get a decent label for this element
+std::string LLDAELoader::getElementLabel(daeElement *element)
+{
+ // if we have a name attribute, use it
+ std::string name = element->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if we have an ID attribute, use it
+ if (element->getID())
+ {
+ return std::string(element->getID());
+ }
+
+ // if we have a parent, use it
+ daeElement* parent = element->getParent();
+ std::string index_string;
+ if (parent)
+ {
+ // retrieve index to distinguish items inside same parent
+ size_t ind = 0;
+ parent->getChildren().find(element, ind);
+ index_string = "_" + boost::lexical_cast<std::string>(ind);
+
+ // if parent has a name or ID, use it
+ std::string name = parent->getAttribute("name");
+ if (!name.length())
+ {
+ name = std::string(parent->getID());
+ }
+
+ if (name.length())
+ {
+ // make sure that index won't mix up with pre-named lod extensions
+ size_t ext_pos = getSuffixPosition(name);
+
+ if (ext_pos == -1)
+ {
+ return name + index_string;
+ }
+ else
+ {
+ return name.insert(ext_pos, index_string);
+ }
+ }
+ }
+
+ // try to use our type
+ daeString element_name = element->getElementName();
+ if (element_name)
+ {
+ return std::string(element_name) + index_string;
+ }
+
+ // if all else fails, use "object"
+ return std::string("object") + index_string;
+}
+
+// static
+size_t LLDAELoader::getSuffixPosition(std::string label)
+{
+ if ((label.find("_LOD") != -1) || (label.find("_PHYS") != -1))
+ {
+ return label.rfind('_');
+ }
+ return -1;
+}
+
+// static
+std::string LLDAELoader::getLodlessLabel(daeElement *element)
+{
+ std::string label = getElementLabel(element);
+ size_t ext_pos = getSuffixPosition(label);
+ if (ext_pos != -1)
+ {
+ return label.substr(0, ext_pos);
+ }
+ return label;
+}
+
+LLColor4 LLDAELoader::getDaeColor(daeElement* element)
+{
+ LLColor4 value;
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ }
+
+ return value;
+}
+
+bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh)
+{
+ LLModel::EModelStatus status = LLModel::NO_ERRORS;
+ domTriangles_Array& tris = mesh->getTriangles_array();
+
+ for (U32 i = 0; i < tris.getCount(); ++i)
+ {
+ domTrianglesRef& tri = tris.get(i);
+
+ status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri);
+ pModel->mStatus = status;
+ if(status != LLModel::NO_ERRORS)
+ {
+ pModel->ClearFacesAndMaterials();
+ return false;
+ }
+ }
+
+ domPolylist_Array& polys = mesh->getPolylist_array();
+ for (U32 i = 0; i < polys.getCount(); ++i)
+ {
+ domPolylistRef& poly = polys.get(i);
+ status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
+
+ if(status != LLModel::NO_ERRORS)
+ {
+ pModel->ClearFacesAndMaterials();
+ return false;
+ }
+ }
+
+ domPolygons_Array& polygons = mesh->getPolygons_array();
+
+ for (U32 i = 0; i < polygons.getCount(); ++i)
+ {
+ domPolygonsRef& poly = polygons.get(i);
+ status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
+
+ if(status != LLModel::NO_ERRORS)
+ {
+ pModel->ClearFacesAndMaterials();
+ return false;
+ }
+ }
+
+ return (status == LLModel::NO_ERRORS);
+}
+
+//static
+LLModel* LLDAELoader::loadModelFromDomMesh(domMesh *mesh)
+{
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ LLModel* ret = new LLModel(volume_params, 0.f);
+ createVolumeFacesFromDomMesh(ret, mesh);
+ if (ret->mLabel.empty())
+ {
+ ret->mLabel = getElementLabel(mesh);
+ }
+ return ret;
+}
+
+//static diff version supports creating multiple models when material counts spill
+// over the 8 face server-side limit
+//
+bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out, U32 submodel_limit)
+{
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ models_out.clear();
+
+ LLModel* ret = new LLModel(volume_params, 0.f);
+
+ std::string model_name = getLodlessLabel(mesh);
+ ret->mLabel = model_name + lod_suffix[mLod];
+
+ llassert(!ret->mLabel.empty());
+
+ // Like a monkey, ready to be shot into space
+ //
+ ret->ClearFacesAndMaterials();
+
+ // Get the whole set of volume faces
+ //
+ addVolumeFacesFromDomMesh(ret, mesh);
+
+ U32 volume_faces = ret->getNumVolumeFaces();
+
+ // Side-steps all manner of issues when splitting models
+ // and matching lower LOD materials to base models
+ //
+ ret->sortVolumeFacesByMaterialName();
+
+ bool normalized = false;
+
+ int submodelID = 0;
+
+ // remove all faces that definitely won't fit into one model and submodel limit
+ U32 face_limit = (submodel_limit + 1) * LL_SCULPT_MESH_MAX_FACES;
+ if (face_limit < volume_faces)
+ {
+ ret->setNumVolumeFaces(face_limit);
+ }
+
+ LLVolume::face_list_t remainder;
+ do
+ {
+ // Insure we do this once with the whole gang and not per-model
+ //
+ if (!normalized && !mNoNormalize)
+ {
+ normalized = true;
+ ret->normalizeVolumeFaces();
+ }
+
+ ret->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder);
+
+ if (!mNoOptimize)
+ {
+ ret->optimizeVolumeFaces();
+ }
+
+ volume_faces = remainder.size();
+
+ models_out.push_back(ret);
+
+ // If we have left-over volume faces, create another model
+ // to absorb them...
+ //
+ if (volume_faces)
+ {
+ LLModel* next = new LLModel(volume_params, 0.f);
+ next->mSubmodelID = ++submodelID;
+ next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod];
+ next->getVolumeFaces() = remainder;
+ next->mNormalizedScale = ret->mNormalizedScale;
+ next->mNormalizedTranslation = ret->mNormalizedTranslation;
+ if ( ret->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES)
+ {
+ next->mMaterialList.assign(ret->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, ret->mMaterialList.end());
+ }
+ ret = next;
+ }
+
+ remainder.clear();
+
+ } while (volume_faces);
+
+ return true;
+}
+
+bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh)
+{
+ if (mesh)
+ {
+ pModel->ClearFacesAndMaterials();
+
+ addVolumeFacesFromDomMesh(pModel, mesh);
+
+ if (pModel->getNumVolumeFaces() > 0)
+ {
+ pModel->normalizeVolumeFaces();
+ pModel->optimizeVolumeFaces();
+
+ if (pModel->getNumVolumeFaces() > 0)
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS() << "no mesh found" << LL_ENDL;
+ }
+
+ return false;
+}
diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h
new file mode 100644
index 0000000000..7d91a6063b
--- /dev/null
+++ b/indra/llprimitive/lldaeloader.h
@@ -0,0 +1,107 @@
+/**
+ * @file lldaeloader.h
+ * @brief LLDAELoader class definition
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLDAELOADER_H
+#define LL_LLDAELOADER_H
+
+#include "llmodelloader.h"
+
+class DAE;
+class daeElement;
+class domProfile_COMMON;
+class domInstance_geometry;
+class domNode;
+class domTranslate;
+class domController;
+class domSkin;
+class domMesh;
+
+class LLDAELoader : public LLModelLoader
+{
+public:
+ typedef std::map<std::string, LLImportMaterial> material_map;
+ typedef std::map<daeElement*, std::vector<LLPointer<LLModel> > > dae_model_map;
+ dae_model_map mModelsMap;
+
+ LLDAELoader(
+ std::string filename,
+ S32 lod,
+ LLModelLoader::load_callback_t load_cb,
+ LLModelLoader::joint_lookup_func_t joint_lookup_func,
+ LLModelLoader::texture_load_func_t texture_load_func,
+ LLModelLoader::state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointMap,
+ JointSet& jointsFromNodes,
+ U32 modelLimit);
+ virtual ~LLDAELoader() ;
+
+ virtual bool OpenFile(const std::string& filename);
+
+protected:
+
+ void processElement(daeElement* element, bool& badElement, DAE* dae);
+ void processDomModel(LLModel* model, DAE* dae, daeElement* pRoot, domMesh* mesh, domSkin* skin);
+
+ material_map getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae);
+ LLImportMaterial profileToMaterial(domProfile_COMMON* material, DAE* dae);
+ LLColor4 getDaeColor(daeElement* element);
+
+ daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
+
+ bool isNodeAJoint( domNode* pNode );
+ void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
+ void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
+ void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
+ void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
+ void buildJointToNodeMappingFromScene( daeElement* pRoot );
+ void processJointToNodeMapping( domNode* pNode );
+ void processChildJoints( domNode* pParentNode );
+
+ bool verifyCount( int expected, int result );
+
+ //Verify that a controller matches vertex counts
+ bool verifyController( domController* pController );
+
+ static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh);
+ static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh);
+
+ static LLModel* loadModelFromDomMesh(domMesh* mesh);
+
+ // Loads a mesh breaking it into one or more models as necessary
+ // to get around volume face limitations while retaining >8 materials
+ //
+ bool loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out, U32 submodel_limit);
+
+ static std::string getElementLabel(daeElement *element);
+ static size_t getSuffixPosition(std::string label);
+ static std::string getLodlessLabel(daeElement *element);
+
+private:
+ U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
+
+};
+#endif // LL_LLDAELLOADER_H
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index ed903146ef..e494c55250 100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -31,18 +31,6 @@
#include "llconvexdecomposition.h"
#include "llsdserialize.h"
#include "llvector4a.h"
-#if LL_MSVC
-#pragma warning (disable : 4263)
-#pragma warning (disable : 4264)
-#endif
-#include "dae.h"
-#include "dae/daeErrorHandler.h"
-#include "dom/domConstants.h"
-#include "dom/domMesh.h"
-#if LL_MSVC
-#pragma warning (default : 4263)
-#pragma warning (default : 4264)
-#endif
#ifdef LL_USESYSTEMLIBS
# include <zlib.h>
@@ -50,8 +38,6 @@
# include "zlib/zlib.h"
#endif
-
-
std::string model_names[] =
{
"lowest_lod",
@@ -65,7 +51,7 @@ const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string);
LLModel::LLModel(LLVolumeParams& params, F32 detail)
: LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0)
- , mPelvisOffset( 0.0f ), mStatus(NO_ERRORS)
+ , mPelvisOffset( 0.0f ), mStatus(NO_ERRORS), mSubmodelID(0)
{
mDecompID = -1;
mLocalID = -1;
@@ -79,939 +65,112 @@ LLModel::~LLModel()
}
}
-
-bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
- domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
+//static
+std::string LLModel::getStatusString(U32 status)
{
- idx_stride = 0;
+ const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow","bad_element"};
- for (U32 j = 0; j < inputs.getCount(); ++j)
+ if(status < INVALID_STATUS)
{
- idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride);
-
- if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
- { //found vertex array
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- domVertices* vertices = (domVertices*) elem.cast();
- if ( !vertices )
- {
- return false;
- }
-
- domInputLocal_Array& v_inp = vertices->getInput_array();
-
-
- for (U32 k = 0; k < v_inp.getCount(); ++k)
- {
- if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
- {
- pos_offset = inputs[j]->getOffset();
-
- const domURIFragmentType& uri = v_inp[k]->getSource();
- daeElementRef elem = uri.getElement();
- pos_source = (domSource*) elem.cast();
- }
-
- if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0)
- {
- norm_offset = inputs[j]->getOffset();
-
- const domURIFragmentType& uri = v_inp[k]->getSource();
- daeElementRef elem = uri.getElement();
- norm_source = (domSource*) elem.cast();
- }
- }
- }
-
- if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
+ if(status_strings[status] == std::string())
{
- //found normal array for this triangle list
- norm_offset = inputs[j]->getOffset();
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- norm_source = (domSource*) elem.cast();
+ //LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL();
}
- else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
- { //found texCoords
- tc_offset = inputs[j]->getOffset();
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- tc_source = (domSource*) elem.cast();
- }
- }
-
- idx_stride += 1;
-
- return true;
-}
-
-LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
-{
- LLVolumeFace face;
- std::vector<LLVolumeFace::VertexData> verts;
- std::vector<U16> indices;
-
- const domInputLocalOffset_Array& inputs = tri->getInput_array();
-
- S32 pos_offset = -1;
- S32 tc_offset = -1;
- S32 norm_offset = -1;
-
- domSource* pos_source = NULL;
- domSource* tc_source = NULL;
- domSource* norm_source = NULL;
-
- S32 idx_stride = 0;
-
- if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source )
- {
- LL_WARNS() << "Could not find dom sources for basic geo data; invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
+ return status_strings[status] ;
}
- if (!pos_source)
- {
- LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- domPRef p = tri->getP();
- domListOfUInts& idx = p->getValue();
-
- domListOfFloats dummy ;
- domListOfFloats& v = (pos_source && pos_source->getFloat_array()) ? pos_source->getFloat_array()->getValue() : dummy ;
- domListOfFloats& tc = (tc_source && tc_source->getFloat_array()) ? tc_source->getFloat_array()->getValue() : dummy ;
- domListOfFloats& n = (norm_source && norm_source->getFloat_array()) ? norm_source->getFloat_array()->getValue() : dummy ;
+ //LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL();
- LLVolumeFace::VertexMapData::PointMap point_map;
-
- U32 index_count = idx.getCount();
- U32 vertex_count = (pos_source && pos_source->getFloat_array()) ? v.getCount() : 0;
- U32 tc_count = (tc_source && tc_source->getFloat_array()) ? tc.getCount() : 0;
- U32 norm_count = (norm_source && norm_source->getFloat_array()) ? n.getCount(): 0;
+ return std::string() ;
+}
- if (vertex_count == 0)
- {
- LL_WARNS() << "Unable to process mesh with empty position array; invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- face.mExtents[0].set(v[0], v[1], v[2]);
- face.mExtents[1].set(v[0], v[1], v[2]);
+void LLModel::offsetMesh( const LLVector3& pivotPoint )
+{
+ LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
- for (U32 i = 0; i < index_count; i += idx_stride)
- {
- LLVolumeFace::VertexData cv;
- if (pos_source)
- {
- // guard against model data specifiying out of range indices or verts
- //
- if (((i + pos_offset) > index_count)
- || ((idx[i+pos_offset]*3+2) > vertex_count))
- {
- LL_WARNS() << "Out of range index data; invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0],
- v[idx[i+pos_offset]*3+1],
- v[idx[i+pos_offset]*3+2]));
-
- if (!cv.getPosition().isFinite3())
- {
- LL_WARNS() << "Nan positional data, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- if (tc_source)
- {
- // guard against model data specifiying out of range indices or tcs
- //
-
- if (((i + tc_offset) > index_count)
- || ((idx[i+tc_offset]*2+1) > tc_count))
- {
- LL_WARNS() << "Out of range TC indices." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
- tc[idx[i+tc_offset]*2+1]);
-
- if (!cv.mTexCoord.isFinite())
- {
- LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- if (norm_source)
- {
- // guard against model data specifiying out of range indices or norms
- //
- if (((i + norm_offset) > index_count)
- || ((idx[i+norm_offset]*3+2) > norm_count))
- {
- LL_WARNS() << "Found out of range norm indices, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
- n[idx[i+norm_offset]*3+1],
- n[idx[i+norm_offset]*3+2]));
-
- if (!cv.getNormal().isFinite3())
- {
- LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- BOOL found = FALSE;
-
- LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
- point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
-
- if (point_iter != point_map.end())
- {
- for (U32 j = 0; j < point_iter->second.size(); ++j)
- {
- if ((point_iter->second)[j] == cv)
- {
- found = TRUE;
- indices.push_back((point_iter->second)[j].mIndex);
- break;
- }
- }
- }
-
- if (!found)
- {
- update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
- verts.push_back(cv);
- if (verts.size() >= 65535)
- {
- //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
- return LLModel::VERTEX_NUMBER_OVERFLOW ;
- }
- U16 index = (U16) (verts.size()-1);
- indices.push_back(index);
-
- LLVolumeFace::VertexMapData d;
- d.setPosition(cv.getPosition());
- d.mTexCoord = cv.mTexCoord;
- d.setNormal(cv.getNormal());
- d.mIndex = index;
- if (point_iter != point_map.end())
- {
- point_iter->second.push_back(d);
- }
- else
- {
- point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
- }
- }
-
- if (indices.size()%3 == 0 && verts.size() >= 65532)
- {
- std::string material;
-
- if (tri->getMaterial())
- {
- material = std::string(tri->getMaterial());
- }
-
- materials.push_back(material);
- face_list.push_back(face);
- face_list.rbegin()->fillFromLegacyData(verts, indices);
- LLVolumeFace& new_face = *face_list.rbegin();
- if (!norm_source)
- {
- //ll_aligned_free_16(new_face.mNormals);
- new_face.mNormals = NULL;
- }
-
- if (!tc_source)
- {
- //ll_aligned_free_16(new_face.mTexCoords);
- new_face.mTexCoords = NULL;
- }
-
- face = LLVolumeFace();
- point_map.clear();
- }
- }
-
- if (!verts.empty())
+ for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )
{
- std::string material;
-
- if (tri->getMaterial())
- {
- material = std::string(tri->getMaterial());
- }
+ std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++;
+ LLVolumeFace& face = *currentFaceIt;
+ LLVector4a *pos = (LLVector4a*) face.mPositions;
- materials.push_back(material);
- face_list.push_back(face);
-
- face_list.rbegin()->fillFromLegacyData(verts, indices);
- LLVolumeFace& new_face = *face_list.rbegin();
- if (!norm_source)
- {
- //ll_aligned_free_16(new_face.mNormals);
- new_face.mNormals = NULL;
- }
-
- if (!tc_source)
+ for (U32 i=0; i<face.mNumVertices; ++i )
{
- //ll_aligned_free_16(new_face.mTexCoords);
- new_face.mTexCoords = NULL;
+ pos[i].add( pivot );
}
}
-
- return LLModel::NO_ERRORS ;
}
-LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly)
+void LLModel::optimizeVolumeFaces()
{
- domPRef p = poly->getP();
- domListOfUInts& idx = p->getValue();
-
- if (idx.getCount() == 0)
- {
- return LLModel::NO_ERRORS ;
- }
-
- const domInputLocalOffset_Array& inputs = poly->getInput_array();
-
-
- domListOfUInts& vcount = poly->getVcount()->getValue();
-
- S32 pos_offset = -1;
- S32 tc_offset = -1;
- S32 norm_offset = -1;
-
- domSource* pos_source = NULL;
- domSource* tc_source = NULL;
- domSource* norm_source = NULL;
-
- S32 idx_stride = 0;
-
- if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
- {
- LL_WARNS() << "Could not get DOM sources for basic geo data, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- LLVolumeFace face;
-
- std::vector<U16> indices;
- std::vector<LLVolumeFace::VertexData> verts;
-
- domListOfFloats v;
- domListOfFloats tc;
- domListOfFloats n;
-
- if (pos_source)
- {
- v = pos_source->getFloat_array()->getValue();
- face.mExtents[0].set(v[0], v[1], v[2]);
- face.mExtents[1].set(v[0], v[1], v[2]);
- }
-
- if (tc_source)
- {
- tc = tc_source->getFloat_array()->getValue();
- }
-
- if (norm_source)
- {
- n = norm_source->getFloat_array()->getValue();
- }
-
- LLVolumeFace::VertexMapData::PointMap point_map;
-
- U32 index_count = idx.getCount();
- U32 vertex_count = pos_source ? v.getCount() : 0;
- U32 tc_count = tc_source ? tc.getCount() : 0;
- U32 norm_count = norm_source ? n.getCount() : 0;
-
- U32 cur_idx = 0;
- for (U32 i = 0; i < vcount.getCount(); ++i)
- { //for each polygon
- U32 first_index = 0;
- U32 last_index = 0;
- for (U32 j = 0; j < vcount[i]; ++j)
- { //for each vertex
-
- LLVolumeFace::VertexData cv;
-
- if (pos_source)
- {
- // guard against model data specifiying out of range indices or verts
- //
- if (((cur_idx + pos_offset) > index_count)
- || ((idx[cur_idx+pos_offset]*3+2) > vertex_count))
- {
- LL_WARNS() << "Out of range position indices, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0],
- v[idx[cur_idx+pos_offset]*3+1],
- v[idx[cur_idx+pos_offset]*3+2]);
-
- if (!cv.getPosition().isFinite3())
- {
- LL_WARNS() << "Found NaN while loading positions from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- }
-
- if (tc_source)
- {
- // guard against model data specifiying out of range indices or tcs
- //
- if (((cur_idx + tc_offset) > index_count)
- || ((idx[cur_idx+tc_offset]*2+1) > tc_count))
- {
- LL_WARNS() << "Out of range TC indices, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
- tc[idx[cur_idx+tc_offset]*2+1]);
-
- if (!cv.mTexCoord.isFinite())
- {
- LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- if (norm_source)
- {
- // guard against model data specifiying out of range indices or norms
- //
- if (((cur_idx + norm_offset) > index_count)
- || ((idx[cur_idx+norm_offset]*3+2) > norm_count))
- {
- LL_WARNS() << "Out of range norm indices, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
-
- cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0],
- n[idx[cur_idx+norm_offset]*3+1],
- n[idx[cur_idx+norm_offset]*3+2]);
-
- if (!cv.getNormal().isFinite3())
- {
- LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- cur_idx += idx_stride;
-
- BOOL found = FALSE;
-
- LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
- LLVector3 pos3(cv.getPosition().getF32ptr());
- point_iter = point_map.find(pos3);
-
- if (point_iter != point_map.end())
- {
- for (U32 k = 0; k < point_iter->second.size(); ++k)
- {
- if ((point_iter->second)[k] == cv)
- {
- found = TRUE;
- U32 index = (point_iter->second)[k].mIndex;
- if (j == 0)
- {
- first_index = index;
- }
- else if (j == 1)
- {
- last_index = index;
- }
- else
- {
- indices.push_back(first_index);
- indices.push_back(last_index);
- indices.push_back(index);
- last_index = index;
- }
-
- break;
- }
- }
- }
-
- if (!found)
- {
- update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
- verts.push_back(cv);
- if (verts.size() >= 65535)
- {
- //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
- return LLModel::VERTEX_NUMBER_OVERFLOW ;
- }
- U16 index = (U16) (verts.size()-1);
-
- if (j == 0)
- {
- first_index = index;
- }
- else if (j == 1)
- {
- last_index = index;
- }
- else
- {
- indices.push_back(first_index);
- indices.push_back(last_index);
- indices.push_back(index);
- last_index = index;
- }
-
- LLVolumeFace::VertexMapData d;
- d.setPosition(cv.getPosition());
- d.mTexCoord = cv.mTexCoord;
- d.setNormal(cv.getNormal());
- d.mIndex = index;
- if (point_iter != point_map.end())
- {
- point_iter->second.push_back(d);
- }
- else
- {
- point_map[pos3].push_back(d);
- }
- }
-
- if (indices.size()%3 == 0 && indices.size() >= 65532)
- {
- std::string material;
-
- if (poly->getMaterial())
- {
- material = std::string(poly->getMaterial());
- }
-
- materials.push_back(material);
- face_list.push_back(face);
- face_list.rbegin()->fillFromLegacyData(verts, indices);
- LLVolumeFace& new_face = *face_list.rbegin();
- if (!norm_source)
- {
- //ll_aligned_free_16(new_face.mNormals);
- new_face.mNormals = NULL;
- }
-
- if (!tc_source)
- {
- //ll_aligned_free_16(new_face.mTexCoords);
- new_face.mTexCoords = NULL;
- }
-
- face = LLVolumeFace();
- verts.clear();
- indices.clear();
- point_map.clear();
- }
- }
- }
-
- if (!verts.empty())
+ for (U32 i = 0; i < getNumVolumeFaces(); ++i)
{
- std::string material;
-
- if (poly->getMaterial())
- {
- material = std::string(poly->getMaterial());
- }
-
- materials.push_back(material);
- face_list.push_back(face);
- face_list.rbegin()->fillFromLegacyData(verts, indices);
-
- LLVolumeFace& new_face = *face_list.rbegin();
- if (!norm_source)
- {
- //ll_aligned_free_16(new_face.mNormals);
- new_face.mNormals = NULL;
- }
-
- if (!tc_source)
- {
- //ll_aligned_free_16(new_face.mTexCoords);
- new_face.mTexCoords = NULL;
- }
+ mVolumeFaces[i].optimize();
}
-
- return LLModel::NO_ERRORS ;
}
-LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolygonsRef& poly)
+struct MaterialBinding
{
- LLVolumeFace face;
- std::vector<U16> indices;
- std::vector<LLVolumeFace::VertexData> verts;
-
- const domInputLocalOffset_Array& inputs = poly->getInput_array();
-
- S32 v_offset = -1;
- S32 n_offset = -1;
- S32 t_offset = -1;
-
- domListOfFloats* v = NULL;
- domListOfFloats* n = NULL;
- domListOfFloats* t = NULL;
-
- U32 stride = 0;
- for (U32 i = 0; i < inputs.getCount(); ++i)
- {
- stride = llmax((U32) inputs[i]->getOffset()+1, stride);
-
- if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0)
- { //found vertex array
- v_offset = inputs[i]->getOffset();
-
- const domURIFragmentType& uri = inputs[i]->getSource();
- daeElementRef elem = uri.getElement();
- domVertices* vertices = (domVertices*) elem.cast();
- if (!vertices)
- {
- LL_WARNS() << "Could not find vertex source, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- domInputLocal_Array& v_inp = vertices->getInput_array();
-
- for (U32 k = 0; k < v_inp.getCount(); ++k)
- {
- if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
- {
- const domURIFragmentType& uri = v_inp[k]->getSource();
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
- if (!src)
- {
- LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- v = &(src->getFloat_array()->getValue());
- }
- }
- }
- else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0)
- {
- n_offset = inputs[i]->getOffset();
- //found normal array for this triangle list
- const domURIFragmentType& uri = inputs[i]->getSource();
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
- if (!src)
- {
- LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- n = &(src->getFloat_array()->getValue());
- }
- else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0)
- { //found texCoords
- t_offset = inputs[i]->getOffset();
- const domURIFragmentType& uri = inputs[i]->getSource();
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
- if (!src)
- {
- LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- t = &(src->getFloat_array()->getValue());
- }
- }
-
- domP_Array& ps = poly->getP_array();
-
- //make a triangle list in <verts>
- for (U32 i = 0; i < ps.getCount(); ++i)
- { //for each polygon
- domListOfUInts& idx = ps[i]->getValue();
- for (U32 j = 0; j < idx.getCount()/stride; ++j)
- { //for each vertex
- if (j > 2)
- {
- U32 size = verts.size();
- LLVolumeFace::VertexData v0 = verts[size-3];
- LLVolumeFace::VertexData v1 = verts[size-1];
-
- verts.push_back(v0);
- verts.push_back(v1);
- }
-
- LLVolumeFace::VertexData vert;
-
-
- if (v)
- {
- U32 v_idx = idx[j*stride+v_offset]*3;
- v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount());
- vert.getPosition().set(v->get(v_idx),
- v->get(v_idx+1),
- v->get(v_idx+2));
-
- if (!vert.getPosition().isFinite3())
- {
- LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
-
- //bounds check n and t lookups because some FBX to DAE converters
- //use negative indices and empty arrays to indicate data does not exist
- //for a particular channel
- if (n && n->getCount() > 0)
- {
- U32 n_idx = idx[j*stride+n_offset]*3;
- n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount());
- vert.getNormal().set(n->get(n_idx),
- n->get(n_idx+1),
- n->get(n_idx+2));
-
- if (!vert.getNormal().isFinite3())
- {
- LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
- else
- {
- vert.getNormal().clear();
- }
-
-
- if (t && t->getCount() > 0)
- {
- U32 t_idx = idx[j*stride+t_offset]*2;
- t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount());
- vert.mTexCoord.setVec(t->get(t_idx),
- t->get(t_idx+1));
-
- if (!vert.mTexCoord.isFinite())
- {
- LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
- return LLModel::BAD_ELEMENT;
- }
- }
- else
- {
- vert.mTexCoord.clear();
- }
-
-
- verts.push_back(vert);
- }
- }
-
- if (verts.empty())
- {
- return LLModel::NO_ERRORS;
- }
-
- face.mExtents[0] = verts[0].getPosition();
- face.mExtents[1] = verts[0].getPosition();
-
- //create a map of unique vertices to indices
- std::map<LLVolumeFace::VertexData, U32> vert_idx;
-
- U32 cur_idx = 0;
- for (U32 i = 0; i < verts.size(); ++i)
- {
- std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.find(verts[i]);
- if (iter == vert_idx.end())
- {
- vert_idx[verts[i]] = cur_idx++;
- }
- }
-
- //build vertex array from map
- std::vector<LLVolumeFace::VertexData> new_verts;
- new_verts.resize(vert_idx.size());
-
- for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter)
- {
- new_verts[iter->second] = iter->first;
- update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition());
- }
-
- //build index array from map
- indices.resize(verts.size());
-
- for (U32 i = 0; i < verts.size(); ++i)
- {
- indices[i] = vert_idx[verts[i]];
- }
-
- // DEBUG just build an expanded triangle list
- /*for (U32 i = 0; i < verts.size(); ++i)
- {
- indices.push_back((U16) i);
- update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition());
- }*/
-
- if (!new_verts.empty())
- {
- std::string material;
-
- if (poly->getMaterial())
- {
- material = std::string(poly->getMaterial());
- }
-
- materials.push_back(material);
- face_list.push_back(face);
- face_list.rbegin()->fillFromLegacyData(new_verts, indices);
-
- LLVolumeFace& new_face = *face_list.rbegin();
- if (!n)
- {
- //ll_aligned_free_16(new_face.mNormals);
- new_face.mNormals = NULL;
- }
-
- if (!t)
- {
- //ll_aligned_free_16(new_face.mTexCoords);
- new_face.mTexCoords = NULL;
- }
- }
-
- return LLModel::NO_ERRORS ;
-}
+ int index;
+ std::string matName;
+};
-//static
-std::string LLModel::getStatusString(U32 status)
+struct MaterialSort
{
- const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow","bad_element"};
-
- if(status < INVALID_STATUS)
+ bool operator()(const MaterialBinding& lhs, const MaterialBinding& rhs)
{
- if(status_strings[status] == std::string())
- {
- LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL ;
- }
- return status_strings[status] ;
+ return LLStringUtil::compareInsensitive(lhs.matName, rhs.matName) < 0;
}
+};
- LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL ;
-
- return std::string() ;
-}
-
-void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh)
+void LLModel::sortVolumeFacesByMaterialName()
{
- domTriangles_Array& tris = mesh->getTriangles_array();
-
- for (U32 i = 0; i < tris.getCount(); ++i)
- {
- domTrianglesRef& tri = tris.get(i);
+ std::vector<MaterialBinding> bindings;
+ bindings.resize(mVolumeFaces.size());
- mStatus = load_face_from_dom_triangles(mVolumeFaces, mMaterialList, tri);
-
- if(mStatus != NO_ERRORS)
+ for (int i = 0; i < bindings.size(); i++)
+ {
+ bindings[i].index = i;
+ if(i < mMaterialList.size())
{
- mVolumeFaces.clear() ;
- mMaterialList.clear() ;
- return ; //abort
+ bindings[i].matName = mMaterialList[i];
}
}
+ std::sort(bindings.begin(), bindings.end(), MaterialSort());
+ std::vector< LLVolumeFace > new_faces;
- domPolylist_Array& polys = mesh->getPolylist_array();
- for (U32 i = 0; i < polys.getCount(); ++i)
+ // remap the faces to be in the same order the mats now are...
+ //
+ new_faces.resize(bindings.size());
+ for (int i = 0; i < bindings.size(); i++)
{
- domPolylistRef& poly = polys.get(i);
- mStatus = load_face_from_dom_polylist(mVolumeFaces, mMaterialList, poly);
-
- if(mStatus != NO_ERRORS)
+ new_faces[i] = mVolumeFaces[bindings[i].index];
+ if(i < mMaterialList.size())
{
- mVolumeFaces.clear() ;
- mMaterialList.clear() ;
- return ; //abort
+ mMaterialList[i] = bindings[i].matName;
}
}
-
- domPolygons_Array& polygons = mesh->getPolygons_array();
-
- for (U32 i = 0; i < polygons.getCount(); ++i)
- {
- domPolygonsRef& poly = polygons.get(i);
- mStatus = load_face_from_dom_polygons(mVolumeFaces, mMaterialList, poly);
- if(mStatus != NO_ERRORS)
- {
- mVolumeFaces.clear() ;
- mMaterialList.clear() ;
- return ; //abort
- }
- }
-
+ mVolumeFaces = new_faces;
}
-BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
+void LLModel::trimVolumeFacesToSize(U32 new_count, LLVolume::face_list_t* remainder)
{
- if (mesh)
- {
- mVolumeFaces.clear();
- mMaterialList.clear();
-
- addVolumeFacesFromDomMesh(mesh);
-
- if (getNumVolumeFaces() > 0)
- {
- normalizeVolumeFaces();
- optimizeVolumeFaces();
-
- if (getNumVolumeFaces() > 0)
- {
- return TRUE;
- }
- }
- }
- else
- {
- LL_WARNS() << "no mesh found" << LL_ENDL;
- }
-
- return FALSE;
-}
+ llassert(new_count <= LL_SCULPT_MESH_MAX_FACES);
-void LLModel::offsetMesh( const LLVector3& pivotPoint )
-{
- LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
-
- for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )
+ if (new_count && (getNumVolumeFaces() > new_count))
{
- std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++;
- LLVolumeFace& face = *currentFaceIt;
- LLVector4a *pos = (LLVector4a*) face.mPositions;
-
- for (U32 i=0; i<face.mNumVertices; ++i )
+ // Copy out remaining volume faces for alternative handling, if provided
+ //
+ if (remainder)
{
- pos[i].add( pivot );
- }
- }
-}
+ (*remainder).assign(mVolumeFaces.begin() + new_count, mVolumeFaces.end());
+ }
-void LLModel::optimizeVolumeFaces()
-{
- for (U32 i = 0; i < getNumVolumeFaces(); ++i)
- {
- mVolumeFaces[i].optimize();
+ // Trim down to the final set of volume faces (now stuffed to the gills!)
+ //
+ mVolumeFaces.resize(new_count);
}
}
@@ -1025,11 +184,6 @@ void LLModel::optimizeVolumeFaces()
// within the unit cube.
void LLModel::normalizeVolumeFaces()
{
-
- // ensure we don't have too many faces
- if (mVolumeFaces.size() > LL_SCULPT_MESH_MAX_FACES)
- mVolumeFaces.resize(LL_SCULPT_MESH_MAX_FACES);
-
if (!mVolumeFaces.empty())
{
LLVector4a min, max;
@@ -1496,68 +650,10 @@ void LLModel::generateNormals(F32 angle_cutoff)
}
}
-//static
-std::string LLModel::getElementLabel(daeElement *element)
-{ // try to get a decent label for this element
- // if we have a name attribute, use it
- std::string name = element->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if we have an ID attribute, use it
- if (element->getID())
- {
- return std::string(element->getID());
- }
-
- // if we have a parent, use it
- daeElement* parent = element->getParent();
- if (parent)
- {
- // if parent has a name, use it
- std::string name = parent->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if parent has an ID, use it
- if (parent->getID())
- {
- return std::string(parent->getID());
- }
- }
-
- // try to use our type
- daeString element_name = element->getElementName();
- if (element_name)
- {
- return std::string(element_name);
- }
-
- // if all else fails, use "object"
- return std::string("object");
-}
-
-//static
-LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)
-{
- LLVolumeParams volume_params;
- volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
- LLModel* ret = new LLModel(volume_params, 0.f);
- ret->createVolumeFacesFromDomMesh(mesh);
- ret->mLabel = getElementLabel(mesh);
- return ret;
-}
std::string LLModel::getName() const
{
- if (!mRequestedLabel.empty())
- return mRequestedLabel;
- else
- return mLabel;
+ return mRequestedLabel.empty() ? mLabel : mRequestedLabel;
}
//static
@@ -1572,7 +668,8 @@ LLSD LLModel::writeModel(
BOOL upload_skin,
BOOL upload_joints,
BOOL nowrite,
- BOOL as_slm)
+ BOOL as_slm,
+ int submodel_id)
{
LLSD mdl;
@@ -1601,6 +698,14 @@ LLSD LLModel::writeModel(
model[LLModel::LOD_PHYSICS] = NULL;
}
}
+ else if (submodel_id)
+ {
+ const LLModel::Decomposition fake_decomp;
+ mdl["secondary"] = true;
+ mdl["submodel_id"] = submodel_id;
+ mdl["physics_convex"] = fake_decomp.asLLSD();
+ model[LLModel::LOD_PHYSICS] = NULL;
+ }
if (as_slm)
{ //save material list names
@@ -1612,7 +717,7 @@ LLSD LLModel::writeModel(
for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)
{
- if (model[idx] && model[idx]->getNumVolumeFaces() > 0)
+ if (model[idx] && (model[idx]->getNumVolumeFaces() > 0) && model[idx]->getVolumeFace(0).mPositions != NULL)
{
LLVector3 min_pos = LLVector3(model[idx]->getVolumeFace(0).mPositions[0].getF32ptr());
LLVector3 max_pos = min_pos;
@@ -1845,6 +950,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
}
}
+ if (mdl.has("submodel_id"))
+ { //write out submodel id
+ header["submodel_id"] = (LLSD::Integer)mdl["submodel_id"];
+ }
+
std::string out[MODEL_NAMES_LENGTH];
for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++)
@@ -2028,7 +1138,9 @@ bool LLModel::loadModel(std::istream& is)
}
}
- static const std::string nm[] =
+ mSubmodelID = header.has("submodel_id") ? header["submodel_id"].asInteger() : false;
+
+ static const std::string lod_name[] =
{
"lowest_lod",
"low_lod",
@@ -2041,8 +1153,8 @@ bool LLModel::loadModel(std::istream& is)
S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
- if (header[nm[lod]]["offset"].asInteger() == -1 ||
- header[nm[lod]]["size"].asInteger() == 0 )
+ if (header[lod_name[lod]]["offset"].asInteger() == -1 ||
+ header[lod_name[lod]]["size"].asInteger() == 0 )
{ //cannot load requested LOD
LL_WARNS() << "LoD data is invalid!" << LL_ENDL;
return false;
@@ -2051,23 +1163,23 @@ bool LLModel::loadModel(std::istream& is)
bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
header["skin"]["size"].asInteger() > 0;
- if (lod == LLModel::LOD_HIGH)
+ if ((lod == LLModel::LOD_HIGH) && !mSubmodelID)
{ //try to load skin info and decomp info
std::ios::pos_type cur_pos = is.tellg();
loadSkinInfo(header, is);
is.seekg(cur_pos);
}
- if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS)
+ if ((lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) && !mSubmodelID)
{
std::ios::pos_type cur_pos = is.tellg();
loadDecomposition(header, is);
is.seekg(cur_pos);
}
- is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+ is.seekg(header[lod_name[lod]]["offset"].asInteger(), std::ios_base::cur);
- if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
+ if (unpackVolumeFaces(is, header[lod_name[lod]]["size"].asInteger()))
{
if (has_skin)
{
@@ -2133,8 +1245,10 @@ bool LLModel::isMaterialListSubset( LLModel* ref )
break;
}
}
+
if (!foundRef)
{
+ LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;
return false;
}
}
@@ -2185,41 +1299,42 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
for (U32 i = 0; i < mMaterialList.size(); i++)
{
index_map[ref->mMaterialList[i]] = i;
- if (!reorder)
- { //if any material name does not match reference, we need to reorder
- reorder = ref->mMaterialList[i] != mMaterialList[i];
- }
+ //if any material name does not match reference, we need to reorder
+ reorder |= ref->mMaterialList[i] != mMaterialList[i];
base_mat.insert(ref->mMaterialList[i]);
cur_mat.insert(mMaterialList[i]);
}
- if (reorder &&
- base_mat == cur_mat) //don't reorder if material name sets don't match
+ if (reorder && (base_mat == cur_mat)) //don't reorder if material name sets don't match
{
std::vector<LLVolumeFace> new_face_list;
- new_face_list.resize(mVolumeFaces.size());
+ new_face_list.resize(mMaterialList.size());
std::vector<std::string> new_material_list;
- new_material_list.resize(mVolumeFaces.size());
+ new_material_list.resize(mMaterialList.size());
//rebuild face list so materials have the same order
//as the reference model
for (U32 i = 0; i < mMaterialList.size(); ++i)
{
U32 ref_idx = index_map[mMaterialList[i]];
- new_face_list[ref_idx] = mVolumeFaces[i];
+ if (i < mVolumeFaces.size())
+ {
+ new_face_list[ref_idx] = mVolumeFaces[i];
+ }
new_material_list[ref_idx] = mMaterialList[i];
}
llassert(new_material_list == ref->mMaterialList);
mVolumeFaces = new_face_list;
- }
- //override material list with reference model ordering
- mMaterialList = ref->mMaterialList;
+ //override material list with reference model ordering
+ mMaterialList = ref->mMaterialList;
+ }
+
return true;
}
@@ -2250,7 +1365,7 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
S32 offset = header["physics_convex"]["offset"].asInteger();
S32 size = header["physics_convex"]["size"].asInteger();
- if (offset >= 0 && size > 0)
+ if (offset >= 0 && size > 0 && !mSubmodelID)
{
is.seekg(offset, std::ios_base::cur);
@@ -2658,3 +1773,227 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
}
}
+bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance)
+{
+ // small area check
+ {
+ LLVector4a edge1; edge1.setSub( a, b );
+ LLVector4a edge2; edge2.setSub( a, c );
+ //////////////////////////////////////////////////////////////////////////
+ /// Linden Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ // If no one edge is more than 10x longer than any other edge, we weaken
+ // the tolerance by a factor of 1e-4f.
+
+ LLVector4a edge3; edge3.setSub( c, b );
+ const F32 len1sq = edge1.dot3(edge1).getF32();
+ const F32 len2sq = edge2.dot3(edge2).getF32();
+ const F32 len3sq = edge3.dot3(edge3).getF32();
+ bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
+ bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
+ bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
+ if ( abOK && acOK && cbOK )
+ {
+ tolerance *= 1e-4f;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /// End Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ LLVector4a cross; cross.setCross3( edge1, edge2 );
+
+ LLVector4a edge1b; edge1b.setSub( b, a );
+ LLVector4a edge2b; edge2b.setSub( b, c );
+ LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
+
+ if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
+ {
+ return true;
+ }
+ }
+
+ // point triangle distance check
+ {
+ LLVector4a Q; Q.setSub(a, b);
+ LLVector4a R; R.setSub(c, b);
+
+ const F32 QQ = dot3fpu(Q, Q);
+ const F32 RR = dot3fpu(R, R);
+ const F32 QR = dot3fpu(R, Q);
+
+ volatile F32 QQRR = QQ * RR;
+ volatile F32 QRQR = QR * QR;
+ F32 Det = (QQRR - QRQR);
+
+ if( Det == 0.0f )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool validate_face(const LLVolumeFace& face)
+{
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ {
+ if (face.mIndices[i] >= face.mNumVertices)
+ {
+ LL_WARNS() << "Face has invalid index." << LL_ENDL;
+ return false;
+ }
+ }
+
+ if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+ {
+ LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
+ return false;
+ }
+
+ /*const LLVector4a scale(0.5f);
+
+ for (U32 i = 0; i < face.mNumIndices; i+=3)
+ {
+ U16 idx1 = face.mIndices[i];
+ U16 idx2 = face.mIndices[i+1];
+ U16 idx3 = face.mIndices[i+2];
+
+ LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
+
+ if (ll_is_degenerate(v1,v2,v3))
+ {
+ llwarns << "Degenerate face found!" << LL_ENDL;
+ return false;
+ }
+ }*/
+
+ return true;
+}
+
+bool validate_model(const LLModel* mdl)
+{
+ if (mdl->getNumVolumeFaces() == 0)
+ {
+ LL_WARNS() << "Model has no faces!" << LL_ENDL;
+ return false;
+ }
+
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ if (mdl->getVolumeFace(i).mNumVertices == 0)
+ {
+ LL_WARNS() << "Face has no vertices." << LL_ENDL;
+ return false;
+ }
+
+ if (mdl->getVolumeFace(i).mNumIndices == 0)
+ {
+ LL_WARNS() << "Face has no indices." << LL_ENDL;
+ return false;
+ }
+
+ if (!validate_face(mdl->getVolumeFace(i)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+LLModelInstance::LLModelInstance(LLSD& data)
+ : LLModelInstanceBase()
+{
+ mLocalMeshID = data["mesh_id"].asInteger();
+ mLabel = data["label"].asString();
+ mTransform.setValue(data["transform"]);
+
+ for (U32 i = 0; i < data["material"].size(); ++i)
+ {
+ LLImportMaterial mat(data["material"][i]);
+ mMaterial[mat.mBinding] = mat;
+ }
+}
+
+
+LLSD LLModelInstance::asLLSD()
+{
+ LLSD ret;
+
+ ret["mesh_id"] = mModel->mLocalID;
+ ret["label"] = mLabel;
+ ret["transform"] = mTransform.getValue();
+
+ U32 i = 0;
+ for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
+ {
+ ret["material"][i++] = iter->second.asLLSD();
+ }
+
+ return ret;
+}
+
+
+LLImportMaterial::~LLImportMaterial()
+{
+}
+
+LLImportMaterial::LLImportMaterial(LLSD& data)
+{
+ mDiffuseMapFilename = data["diffuse"]["filename"].asString();
+ mDiffuseMapLabel = data["diffuse"]["label"].asString();
+ mDiffuseColor.setValue(data["diffuse"]["color"]);
+ mFullbright = data["fullbright"].asBoolean();
+ mBinding = data["binding"].asString();
+}
+
+
+LLSD LLImportMaterial::asLLSD()
+{
+ LLSD ret;
+
+ ret["diffuse"]["filename"] = mDiffuseMapFilename;
+ ret["diffuse"]["label"] = mDiffuseMapLabel;
+ ret["diffuse"]["color"] = mDiffuseColor.getValue();
+ ret["fullbright"] = mFullbright;
+ ret["binding"] = mBinding;
+
+ return ret;
+}
+
+bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
+{
+
+ if (mDiffuseMapID != rhs.mDiffuseMapID)
+ {
+ return mDiffuseMapID < rhs.mDiffuseMapID;
+ }
+
+ if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
+ {
+ return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
+ }
+
+ if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
+ {
+ return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
+ }
+
+ if (mDiffuseColor != rhs.mDiffuseColor)
+ {
+ return mDiffuseColor < rhs.mDiffuseColor;
+ }
+
+ if (mBinding != rhs.mBinding)
+ {
+ return mBinding < rhs.mBinding;
+ }
+
+ return mFullbright < rhs.mFullbright;
+}
+
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index aaafc55258..ae602c09df 100755
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -31,6 +31,7 @@
#include "llvolume.h"
#include "v4math.h"
#include "m4math.h"
+#include <queue>
class daeElement;
class domMesh;
@@ -138,15 +139,16 @@ public:
BOOL upload_skin,
BOOL upload_joints,
BOOL nowrite = FALSE,
- BOOL as_slm = FALSE);
+ BOOL as_slm = FALSE,
+ int submodel_id = 0);
static LLSD writeModelToStream(
std::ostream& ostr,
LLSD& mdl,
BOOL nowrite = FALSE, BOOL as_slm = FALSE);
+
+ void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
- static LLModel* loadModelFromDomMesh(domMesh* mesh);
- static std::string getElementLabel(daeElement* element);
std::string getName() const;
std::string getMetric() const {return mMetric;}
EModelStatus getStatus() const {return mStatus;}
@@ -169,20 +171,25 @@ public:
void addFace(const LLVolumeFace& face);
+ void sortVolumeFacesByMaterialName();
void normalizeVolumeFaces();
+ void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
LLVector3 getTransformedCenter(const LLMatrix4& mat);
-
+
//reorder face list based on mMaterialList in this and reference so
//order matches that of reference (material ordering touchup)
bool matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCnt );
bool isMaterialListSubset( LLModel* ref );
bool needToAddFaces( LLModel* ref, int& refFaceCnt, int& modelFaceCnt );
-
- std::vector<std::string> mMaterialList;
+ typedef std::vector<std::string> material_list;
+
+ material_list mMaterialList;
+
+ material_list& getMaterialList() { return mMaterialList; }
//data used for skin weights
class JointWeight
@@ -275,9 +282,115 @@ public:
Decomposition mPhysics;
EModelStatus mStatus ;
+
+ int mSubmodelID;
+};
+
+typedef std::vector<LLPointer<LLModel> > model_list;
+typedef std::queue<LLPointer<LLModel> > model_queue;
+
+class LLModelMaterialBase
+{
+public:
+ std::string mDiffuseMapFilename;
+ std::string mDiffuseMapLabel;
+ std::string mBinding;
+ LLColor4 mDiffuseColor;
+ bool mFullbright;
+
+ LLModelMaterialBase()
+ : mFullbright(false)
+ {
+ mDiffuseColor.set(1,1,1,1);
+ }
+};
+
+class LLImportMaterial : public LLModelMaterialBase
+{
+public:
+ friend class LLMeshUploadThread;
+ friend class LLModelPreview;
+
+ bool operator<(const LLImportMaterial &params) const;
+
+ LLImportMaterial() : LLModelMaterialBase()
+ {
+ mDiffuseColor.set(1,1,1,1);
+ }
+
+ LLImportMaterial(LLSD& data);
+ virtual ~LLImportMaterial();
+
+ LLSD asLLSD();
+
+ const LLUUID& getDiffuseMap() const { return mDiffuseMapID; }
+ void setDiffuseMap(const LLUUID& texId) { mDiffuseMapID = texId; }
+
protected:
- void addVolumeFacesFromDomMesh(domMesh* mesh);
- virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
+
+ LLUUID mDiffuseMapID;
+ void* mOpaqueData; // allow refs to viewer/platform-specific structs for each material
+ // currently only stores an LLPointer< LLViewerFetchedTexture > > to
+ // maintain refs to textures associated with each material for free
+ // ref counting.
};
+typedef std::map<std::string, LLImportMaterial> material_map;
+
+class LLModelInstanceBase
+{
+public:
+ LLPointer<LLModel> mModel;
+ LLPointer<LLModel> mLOD[5];
+ LLUUID mMeshID;
+
+ LLMatrix4 mTransform;
+ material_map mMaterial;
+
+ LLModelInstanceBase(LLModel* model, LLMatrix4& transform, material_map& materials)
+ : mModel(model), mTransform(transform), mMaterial(materials)
+ {
+ }
+
+ LLModelInstanceBase()
+ : mModel(NULL)
+ {
+ }
+};
+
+typedef std::vector<LLModelInstanceBase> model_instance_list;
+
+class LLModelInstance : public LLModelInstanceBase
+{
+public:
+ std::string mLabel;
+ LLUUID mMeshID;
+ S32 mLocalMeshID;
+
+ LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, material_map& materials)
+ : LLModelInstanceBase(model, transform, materials), mLabel(label)
+ {
+ mLocalMeshID = -1;
+ }
+
+ LLModelInstance(LLSD& data);
+
+ LLSD asLLSD();
+};
+
+#define LL_DEGENERACY_TOLERANCE 1e-7f
+
+inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
+{
+ volatile F32 p0 = a[0] * b[0];
+ volatile F32 p1 = a[1] * b[1];
+ volatile F32 p2 = a[2] * b[2];
+ return p0 + p1 + p2;
+}
+
+bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE);
+
+bool validate_face(const LLVolumeFace& face);
+bool validate_model(const LLModel* mdl);
+
#endif //LL_LLMODEL_H
diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
new file mode 100644
index 0000000000..81d92d151b
--- /dev/null
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -0,0 +1,640 @@
+/**
+ * @file llmodelloader.cpp
+ * @brief LLModelLoader class implementation
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llmodelloader.h"
+#include "llsdserialize.h"
+#include "lljoint.h"
+#include "llcallbacklist.h"
+
+#include "glh/glh_linear.h"
+#include "llmatrix4a.h"
+#include <boost/bind.hpp>
+
+std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
+
+void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
+{
+ LLVector4a box[] =
+ {
+ LLVector4a(-1, 1,-1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a(-1,-1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a( 1, 1, 1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a( 1,-1, 1),
+ };
+
+ for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
+ {
+ const LLVolumeFace& face = model->getVolumeFace(j);
+
+ LLVector4a center;
+ center.setAdd(face.mExtents[0], face.mExtents[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(face.mExtents[1],face.mExtents[0]);
+ size.mul(0.5f);
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector4a t;
+ t.setMul(size, box[i]);
+ t.add(center);
+
+ LLVector4a v;
+
+ mat.affineTransform(t, v);
+
+ if (first_transform)
+ {
+ first_transform = FALSE;
+ min = max = v;
+ }
+ else
+ {
+ update_min_max(min, max, v);
+ }
+ }
+ }
+}
+
+void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
+{
+ LLVector4a mina, maxa;
+ LLMatrix4a mata;
+
+ mata.loadu(mat);
+ mina.load3(min.mV);
+ maxa.load3(max.mV);
+
+ stretch_extents(model, mata, mina, maxa, first_transform);
+
+ min.set(mina.getF32ptr());
+ max.set(maxa.getF32ptr());
+}
+
+//-----------------------------------------------------------------------------
+// LLModelLoader
+//-----------------------------------------------------------------------------
+LLModelLoader::LLModelLoader(
+ std::string filename,
+ S32 lod,
+ load_callback_t load_cb,
+ joint_lookup_func_t joint_lookup_func,
+ texture_load_func_t texture_load_func,
+ state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointMap,
+ JointSet& jointsFromNodes )
+: mJointList( jointMap )
+, mJointsFromNode( jointsFromNodes )
+, LLThread("Model Loader")
+, mFilename(filename)
+, mLod(lod)
+, mFirstTransform(TRUE)
+, mNumOfFetchingTextures(0)
+, mLoadCallback(load_cb)
+, mJointLookupFunc(joint_lookup_func)
+, mTextureLoadFunc(texture_load_func)
+, mStateCallback(state_cb)
+, mOpaqueData(opaque_userdata)
+, mNoNormalize(false)
+, mNoOptimize(false)
+, mCacheOnlyHitIfRigged(false)
+{
+ mJointMap["mPelvis"] = "mPelvis";
+ mJointMap["mTorso"] = "mTorso";
+ mJointMap["mChest"] = "mChest";
+ mJointMap["mNeck"] = "mNeck";
+ mJointMap["mHead"] = "mHead";
+ mJointMap["mSkull"] = "mSkull";
+ mJointMap["mEyeRight"] = "mEyeRight";
+ mJointMap["mEyeLeft"] = "mEyeLeft";
+ mJointMap["mCollarLeft"] = "mCollarLeft";
+ mJointMap["mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["mElbowLeft"] = "mElbowLeft";
+ mJointMap["mWristLeft"] = "mWristLeft";
+ mJointMap["mCollarRight"] = "mCollarRight";
+ mJointMap["mShoulderRight"] = "mShoulderRight";
+ mJointMap["mElbowRight"] = "mElbowRight";
+ mJointMap["mWristRight"] = "mWristRight";
+ mJointMap["mHipRight"] = "mHipRight";
+ mJointMap["mKneeRight"] = "mKneeRight";
+ mJointMap["mAnkleRight"] = "mAnkleRight";
+ mJointMap["mFootRight"] = "mFootRight";
+ mJointMap["mToeRight"] = "mToeRight";
+ mJointMap["mHipLeft"] = "mHipLeft";
+ mJointMap["mKneeLeft"] = "mKneeLeft";
+ mJointMap["mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["mFootLeft"] = "mFootLeft";
+ mJointMap["mToeLeft"] = "mToeLeft";
+
+ mJointMap["avatar_mPelvis"] = "mPelvis";
+ mJointMap["avatar_mTorso"] = "mTorso";
+ mJointMap["avatar_mChest"] = "mChest";
+ mJointMap["avatar_mNeck"] = "mNeck";
+ mJointMap["avatar_mHead"] = "mHead";
+ mJointMap["avatar_mSkull"] = "mSkull";
+ mJointMap["avatar_mEyeRight"] = "mEyeRight";
+ mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
+ mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
+ mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
+ mJointMap["avatar_mWristLeft"] = "mWristLeft";
+ mJointMap["avatar_mCollarRight"] = "mCollarRight";
+ mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
+ mJointMap["avatar_mElbowRight"] = "mElbowRight";
+ mJointMap["avatar_mWristRight"] = "mWristRight";
+ mJointMap["avatar_mHipRight"] = "mHipRight";
+ mJointMap["avatar_mKneeRight"] = "mKneeRight";
+ mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
+ mJointMap["avatar_mFootRight"] = "mFootRight";
+ mJointMap["avatar_mToeRight"] = "mToeRight";
+ mJointMap["avatar_mHipLeft"] = "mHipLeft";
+ mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
+ mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["avatar_mFootLeft"] = "mFootLeft";
+ mJointMap["avatar_mToeLeft"] = "mToeLeft";
+
+
+ mJointMap["hip"] = "mPelvis";
+ mJointMap["abdomen"] = "mTorso";
+ mJointMap["chest"] = "mChest";
+ mJointMap["neck"] = "mNeck";
+ mJointMap["head"] = "mHead";
+ mJointMap["figureHair"] = "mSkull";
+ mJointMap["lCollar"] = "mCollarLeft";
+ mJointMap["lShldr"] = "mShoulderLeft";
+ mJointMap["lForeArm"] = "mElbowLeft";
+ mJointMap["lHand"] = "mWristLeft";
+ mJointMap["rCollar"] = "mCollarRight";
+ mJointMap["rShldr"] = "mShoulderRight";
+ mJointMap["rForeArm"] = "mElbowRight";
+ mJointMap["rHand"] = "mWristRight";
+ mJointMap["rThigh"] = "mHipRight";
+ mJointMap["rShin"] = "mKneeRight";
+ mJointMap["rFoot"] = "mFootRight";
+ mJointMap["lThigh"] = "mHipLeft";
+ mJointMap["lShin"] = "mKneeLeft";
+ mJointMap["lFoot"] = "mFootLeft";
+
+ //move into joint mapper class
+ //1. joints for joint offset verification
+ mMasterJointList.push_front("mPelvis");
+ mMasterJointList.push_front("mTorso");
+ mMasterJointList.push_front("mChest");
+ mMasterJointList.push_front("mNeck");
+ mMasterJointList.push_front("mHead");
+ mMasterJointList.push_front("mCollarLeft");
+ mMasterJointList.push_front("mShoulderLeft");
+ mMasterJointList.push_front("mElbowLeft");
+ mMasterJointList.push_front("mWristLeft");
+ mMasterJointList.push_front("mCollarRight");
+ mMasterJointList.push_front("mShoulderRight");
+ mMasterJointList.push_front("mElbowRight");
+ mMasterJointList.push_front("mWristRight");
+ mMasterJointList.push_front("mHipRight");
+ mMasterJointList.push_front("mKneeRight");
+ mMasterJointList.push_front("mFootRight");
+ mMasterJointList.push_front("mHipLeft");
+ mMasterJointList.push_front("mKneeLeft");
+ mMasterJointList.push_front("mFootLeft");
+
+ //2. legacy joint list - used to verify rigs that will not be using joint offsets
+ mMasterLegacyJointList.push_front("mPelvis");
+ mMasterLegacyJointList.push_front("mTorso");
+ mMasterLegacyJointList.push_front("mChest");
+ mMasterLegacyJointList.push_front("mNeck");
+ mMasterLegacyJointList.push_front("mHead");
+ mMasterLegacyJointList.push_front("mHipRight");
+ mMasterLegacyJointList.push_front("mKneeRight");
+ mMasterLegacyJointList.push_front("mFootRight");
+ mMasterLegacyJointList.push_front("mHipLeft");
+ mMasterLegacyJointList.push_front("mKneeLeft");
+ mMasterLegacyJointList.push_front("mFootLeft");
+
+ assert_main_thread();
+ sActiveLoaderList.push_back(this) ;
+}
+
+LLModelLoader::~LLModelLoader()
+{
+ assert_main_thread();
+ sActiveLoaderList.remove(this);
+}
+
+void LLModelLoader::run()
+{
+ doLoadModel();
+ doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
+}
+
+bool LLModelLoader::doLoadModel()
+{
+ //first, look for a .slm file of the same name that was modified later
+ //than the .dae
+
+ if (mTrySLM)
+ {
+ std::string filename = mFilename;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ filename.replace(i, filename.size()-1, ".slm");
+ llstat slm_status;
+ if (LLFile::stat(filename, &slm_status) == 0)
+ { //slm file exists
+ llstat dae_status;
+ if (LLFile::stat(mFilename, &dae_status) != 0 ||
+ dae_status.st_mtime < slm_status.st_mtime)
+ {
+ if (loadFromSLM(filename))
+ { //slm successfully loaded, if this fails, fall through and
+ //try loading from dae
+
+ mLod = -1; //successfully loading from an slm implicitly sets all
+ //LoDs
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return OpenFile(mFilename);
+}
+
+void LLModelLoader::setLoadState(U32 state)
+{
+ mStateCallback(state, mOpaqueData);
+}
+
+bool LLModelLoader::loadFromSLM(const std::string& filename)
+{
+ //only need to populate mScene with data from slm
+ llstat stat;
+
+ if (LLFile::stat(filename, &stat))
+ { //file does not exist
+ return false;
+ }
+
+ S32 file_size = (S32) stat.st_size;
+
+ llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+ LLSD data;
+ LLSDSerialize::fromBinary(data, ifstream, file_size);
+ ifstream.close();
+
+ //build model list for each LoD
+ model_list model[LLModel::NUM_LODS];
+
+ if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
+ { //unsupported version
+ return false;
+ }
+
+ LLSD& mesh = data["mesh"];
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ for (U32 i = 0; i < mesh.size(); ++i)
+ {
+ std::stringstream str(mesh[i].asString());
+ LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
+ if (loaded_model->loadModel(str))
+ {
+ loaded_model->mLocalID = i;
+ model[lod].push_back(loaded_model);
+
+ if (lod == LLModel::LOD_HIGH)
+ {
+ if (!loaded_model->mSkinInfo.mJointNames.empty())
+ {
+ //check to see if rig is valid
+ critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
+ }
+ else if (mCacheOnlyHitIfRigged)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (model[LLModel::LOD_HIGH].empty())
+ { //failed to load high lod
+ return false;
+ }
+
+ //load instance list
+ model_instance_list instance_list;
+
+ LLSD& instance = data["instance"];
+
+ for (U32 i = 0; i < instance.size(); ++i)
+ {
+ //deserialize instance list
+ instance_list.push_back(LLModelInstance(instance[i]));
+
+ //match up model instance pointers
+ S32 idx = instance_list[i].mLocalMeshID;
+ std::string instance_label = instance_list[i].mLabel;
+
+ for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ if (!model[lod].empty())
+ {
+ if (idx >= model[lod].size())
+ {
+ if (model[lod].size())
+ {
+ instance_list[i].mLOD[lod] = model[lod][0];
+ }
+ else
+ {
+ instance_list[i].mLOD[lod] = NULL;
+ }
+ continue;
+ }
+
+ if (model[lod][idx]
+ && model[lod][idx]->mLabel.empty()
+ && !instance_label.empty())
+ {
+ // restore model names
+ std::string name = instance_label;
+ switch (lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+ model[lod][idx]->mLabel = name;
+ }
+
+ instance_list[i].mLOD[lod] = model[lod][idx];
+ }
+ }
+
+ if (!instance_list[i].mModel)
+ instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
+ }
+
+ // Set name for UI to use
+ std::string name = data["name"];
+ if (!name.empty())
+ {
+ model[LLModel::LOD_HIGH][0]->mRequestedLabel = name;
+ }
+
+
+ //convert instance_list to mScene
+ mFirstTransform = TRUE;
+ for (U32 i = 0; i < instance_list.size(); ++i)
+ {
+ LLModelInstance& cur_instance = instance_list[i];
+ mScene[cur_instance.mTransform].push_back(cur_instance);
+ stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
+ }
+
+ setLoadState( DONE );
+
+ return true;
+}
+
+//static
+bool LLModelLoader::isAlive(LLModelLoader* loader)
+{
+ if(!loader)
+ {
+ return false ;
+ }
+
+ std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
+ for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
+
+ return *iter == loader ;
+}
+
+void LLModelLoader::loadModelCallback()
+{
+ mLoadCallback(mScene,mModelList,mLod, mOpaqueData);
+
+ while (!isStopped())
+ { //wait until this thread is stopped before deleting self
+ apr_sleep(100);
+ }
+
+ //double check if "this" is valid before deleting it, in case it is aborted during running.
+ if(!isAlive(this))
+ {
+ return ;
+ }
+
+ delete this;
+}
+
+//-----------------------------------------------------------------------------
+// critiqueRigForUploadApplicability()
+//-----------------------------------------------------------------------------
+void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
+{
+ critiqueJointToNodeMappingFromScene();
+
+ //Determines the following use cases for a rig:
+ //1. It is suitable for upload with skin weights & joint positions, or
+ //2. It is suitable for upload as standard av with just skin weights
+
+ bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
+ bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
+
+ //It's OK that both could end up being true, both default to false
+ if ( isJointPositionUploadOK )
+ {
+ setRigValidForJointPositionUpload( true );
+ }
+
+ if ( isRigLegacyOK)
+ {
+ setLegacyRigValid( true );
+ }
+
+}
+//-----------------------------------------------------------------------------
+// critiqueJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLModelLoader::critiqueJointToNodeMappingFromScene( void )
+{
+ //Do the actual nodes back the joint listing from the dae?
+ //if yes then this is a fully rigged asset, otherwise it's just a partial rig
+
+ JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin();
+ JointSet::iterator jointsFromNodeEndIt = mJointsFromNode.end();
+ bool result = true;
+
+ if ( !mJointsFromNode.empty() )
+ {
+ for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
+ {
+ std::string name = *jointsFromNodeIt;
+ if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
+ {
+ continue;
+ }
+ else
+ {
+ LL_INFOS() <<"critiqueJointToNodeMappingFromScene is missing a: " << name << LL_ENDL;
+ result = false;
+ }
+ }
+ }
+ else
+ {
+ result = false;
+ }
+
+ //Determines the following use cases for a rig:
+ //1. Full av rig w/1-1 mapping from the scene and joint array
+ //2. Partial rig but w/o parity between the scene and joint array
+ if ( result )
+ {
+ setRigWithSceneParity( true );
+ }
+}
+//-----------------------------------------------------------------------------
+// isRigLegacy()
+//-----------------------------------------------------------------------------
+bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
+{
+ //No joints in asset
+ if ( jointListFromAsset.size() == 0 )
+ {
+ return false;
+ }
+
+ bool result = false;
+
+ JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
+ JointSet :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
+ break;
+ }
+ }
+ return result;
+}
+//-----------------------------------------------------------------------------
+// isRigSuitableForJointPositionUpload()
+//-----------------------------------------------------------------------------
+bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
+{
+ bool result = false;
+
+ JointSet :: const_iterator masterJointIt = mMasterJointList.begin();
+ JointSet :: const_iterator masterJointEndIt = mMasterJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
+ break;
+ }
+ }
+ return result;
+}
+
+
+//called in the main thread
+void LLModelLoader::loadTextures()
+{
+ BOOL is_paused = isPaused() ;
+ pause() ; //pause the loader
+
+ for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
+ {
+ for(U32 i = 0 ; i < iter->second.size(); i++)
+ {
+ for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
+ j != iter->second[i].mMaterial.end(); ++j)
+ {
+ LLImportMaterial& material = j->second;
+
+ if(!material.mDiffuseMapFilename.empty())
+ {
+ mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
+ }
+ }
+ }
+ }
+
+ if(!is_paused)
+ {
+ unpause() ;
+ }
+}
diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h
new file mode 100644
index 0000000000..bb4d06dca3
--- /dev/null
+++ b/indra/llprimitive/llmodelloader.h
@@ -0,0 +1,212 @@
+/**
+ * @file llmodelloader.h
+ * @brief LLModelLoader class definition
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMODELLOADER_H
+#define LL_LLMODELLOADER_H
+
+#include "llmodel.h"
+#include "llthread.h"
+#include <boost/function.hpp>
+#include <list>
+
+class LLJoint;
+
+typedef std::map<std::string, LLMatrix4> JointTransformMap;
+typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
+typedef std::map<std::string, std::string> JointMap;
+typedef std::deque<std::string> JointSet;
+
+const S32 SLM_SUPPORTED_VERSION = 3;
+const S32 NUM_LOD = 4;
+
+class LLModelLoader : public LLThread
+{
+public:
+
+ typedef std::map<std::string, LLImportMaterial> material_map;
+ typedef std::vector<LLPointer<LLModel > > model_list;
+ typedef std::vector<LLModelInstance> model_instance_list;
+ typedef std::map<LLMatrix4, model_instance_list > scene;
+
+ // Callback with loaded model data and loaded LoD
+ //
+ typedef boost::function<void (scene&,model_list&,S32,void*) > load_callback_t;
+
+ // Function to provide joint lookup by name
+ // (within preview avi skeleton, for example)
+ //
+ typedef boost::function<LLJoint* (const std::string&,void*) > joint_lookup_func_t;
+
+ // Func to load and associate material with all it's textures,
+ // returned value is the number of textures loaded
+ // intentionally non-const so func can modify material to
+ // store platform-specific data
+ //
+ typedef boost::function<U32 (LLImportMaterial&,void*) > texture_load_func_t;
+
+ // Callback to inform client of state changes
+ // during loading process (errors will be reported
+ // as state changes here as well)
+ //
+ typedef boost::function<void (U32,void*) > state_callback_t;
+
+ typedef enum
+ {
+ STARTING = 0,
+ READING_FILE,
+ CREATING_FACES,
+ GENERATING_VERTEX_BUFFERS,
+ GENERATING_LOD,
+ DONE,
+ ERROR_PARSING, //basically loading failed
+ ERROR_MATERIALS,
+ ERROR_PASSWORD_REQUIRED,
+ ERROR_NEED_MORE_MEMORY,
+ ERROR_INVALID_FILE,
+ ERROR_LOADER_SETUP,
+ ERROR_INVALID_PARAMETERS,
+ ERROR_OUT_OF_RANGE,
+ ERROR_FILE_VERSION_INVALID,
+ ERROR_MODEL // this error should always be last in this list, error code is passed as ERROR_MODEL+error_code
+ } eLoadState;
+
+ U32 mState;
+ std::string mFilename;
+
+ S32 mLod;
+
+ LLMatrix4 mTransform;
+ BOOL mFirstTransform;
+ LLVector3 mExtents[2];
+
+ bool mTrySLM;
+ bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
+
+ model_list mModelList;
+ scene mScene;
+
+ typedef std::queue<LLPointer<LLModel> > model_queue;
+
+ //queue of models that need a physics rep
+ model_queue mPhysicsQ;
+
+ //map of avatar joints as named in COLLADA assets to internal joint names
+ JointMap mJointMap;
+ JointTransformMap& mJointList;
+ JointSet& mJointsFromNode;
+
+ LLModelLoader(
+ std::string filename,
+ S32 lod,
+ LLModelLoader::load_callback_t load_cb,
+ LLModelLoader::joint_lookup_func_t joint_lookup_func,
+ LLModelLoader::texture_load_func_t texture_load_func,
+ LLModelLoader::state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointMap,
+ JointSet& jointsFromNodes);
+ virtual ~LLModelLoader() ;
+
+ virtual void setNoNormalize() { mNoNormalize = true; }
+ virtual void setNoOptimize() { mNoOptimize = true; }
+
+ virtual void run();
+
+ // Will try SLM or derived class OpenFile as appropriate
+ //
+ virtual bool doLoadModel();
+
+ // Derived classes need to provide their parsing of files here
+ //
+ virtual bool OpenFile(const std::string& filename) = 0;
+
+ bool loadFromSLM(const std::string& filename);
+
+ void loadModelCallback();
+ void loadTextures() ; //called in the main thread.
+ void setLoadState(U32 state);
+
+
+
+ S32 mNumOfFetchingTextures ; //updated in the main thread
+ bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
+
+ bool verifyCount( int expected, int result );
+
+ //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
+ void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
+ void critiqueJointToNodeMappingFromScene( void );
+
+ //Determines if a rig is a legacy from the joint list
+ bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
+
+ //Determines if a rig is suitable for upload
+ bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
+
+ void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
+ const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
+
+ const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
+ void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
+
+ const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
+ void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
+
+ //-----------------------------------------------------------------------------
+ // isNodeAJoint()
+ //-----------------------------------------------------------------------------
+ bool isNodeAJoint(const char* name)
+ {
+ return mJointMap.find(name) != mJointMap.end();
+ }
+
+protected:
+
+ LLModelLoader::load_callback_t mLoadCallback;
+ LLModelLoader::joint_lookup_func_t mJointLookupFunc;
+ LLModelLoader::texture_load_func_t mTextureLoadFunc;
+ LLModelLoader::state_callback_t mStateCallback;
+ void* mOpaqueData;
+
+ bool mRigParityWithScene;
+ bool mRigValidJointUpload;
+ bool mLegacyRigValid;
+
+ bool mNoNormalize;
+ bool mNoOptimize;
+
+ JointSet mMasterJointList;
+ JointSet mMasterLegacyJointList;
+ JointTransformMap mJointTransformMap;
+
+ static std::list<LLModelLoader*> sActiveLoaderList;
+ static bool isAlive(LLModelLoader* loader) ;
+};
+class LLMatrix4a;
+void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform);
+void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform);
+
+#endif // LL_LLMODELLOADER_H
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 29747cb09c..9eff74f1e8 100755
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -317,9 +317,9 @@ S32 LLPrimitive::setTEMaterialID(const U8 index, const LLMaterialID& pMaterialID
return mTextureList.setMaterialID(index, pMaterialID);
}
-S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
- return mTextureList.setMaterialParams(index, pMaterialParams);
+ return mTextureList.setMaterialParams(index, pMaterialParams, isInitFromServer);
}
LLMaterialPtr LLPrimitive::getTEMaterialParams(const U8 index)
@@ -1869,9 +1869,12 @@ BOOL LLSculptParams::pack(LLDataPacker &dp) const
BOOL LLSculptParams::unpack(LLDataPacker &dp)
{
- dp.unpackUUID(mSculptTexture, "texture");
- dp.unpackU8(mSculptType, "type");
-
+ U8 type;
+ LLUUID id;
+ dp.unpackUUID(id, "texture");
+ dp.unpackU8(type, "type");
+
+ setSculptTexture(id, type);
return TRUE;
}
@@ -1896,8 +1899,7 @@ bool LLSculptParams::operator==(const LLNetworkData& data) const
void LLSculptParams::copy(const LLNetworkData& data)
{
const LLSculptParams *param = (LLSculptParams*)&data;
- mSculptTexture = param->mSculptTexture;
- mSculptType = param->mSculptType;
+ setSculptTexture(param->mSculptTexture, param->mSculptType);
}
@@ -1915,20 +1917,38 @@ LLSD LLSculptParams::asLLSD() const
bool LLSculptParams::fromLLSD(LLSD& sd)
{
const char *w;
- w = "texture";
+ U8 type;
+ w = "type";
if (sd.has(w))
{
- setSculptTexture( sd[w] );
- } else goto fail;
- w = "type";
+ type = sd[w].asInteger();
+ }
+ else return false;
+
+ w = "texture";
if (sd.has(w))
{
- setSculptType( (U8)sd[w].asInteger() );
- } else goto fail;
-
+ setSculptTexture(sd[w], type);
+ }
+ else return false;
+
return true;
- fail:
- return false;
+}
+
+void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type)
+{
+ U8 type = sculpt_type & LL_SCULPT_TYPE_MASK;
+ U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK;
+ if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX)
+ {
+ mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
+ mSculptType = LL_SCULPT_TYPE_SPHERE;
+ }
+ else
+ {
+ mSculptTexture = texture_id;
+ mSculptType = sculpt_type;
+ }
}
//============================================================================
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 1bf83e36b4..54870fbb10 100755
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -259,9 +259,8 @@ public:
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
- void setSculptTexture(const LLUUID& id) { mSculptTexture = id; }
+ void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type);
LLUUID getSculptTexture() const { return mSculptTexture; }
- void setSculptType(U8 type) { mSculptType = type; }
U8 getSculptType() const { return mSculptType; }
};
@@ -385,7 +384,7 @@ public:
virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
virtual S32 setTEGlow(const U8 te, const F32 glow);
virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
- virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
+ virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed
virtual void setTESelected(const U8 te, bool sel);
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
index f4f08248b8..6aae2f97c6 100755
--- a/indra/llprimitive/llprimtexturelist.cpp
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -368,11 +368,18 @@ S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMateri
return TEM_CHANGE_NONE;
}
-S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
if (index < mEntryList.size())
{
- return mEntryList[index]->setMaterialParams(pMaterialParams);
+ if (!isInitFromServer && mEntryList[index]->isMatParamsInitFromServer())
+ {
+ return TEM_CHANGE_NONE;
+ }
+ else
+ {
+ return mEntryList[index]->setMaterialParams(pMaterialParams);
+ }
}
return TEM_CHANGE_NONE;
}
diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h
index 49c636e40f..63e6372405 100755
--- a/indra/llprimitive/llprimtexturelist.h
+++ b/indra/llprimitive/llprimtexturelist.h
@@ -105,7 +105,7 @@ public:
S32 setMediaFlags(const U8 index, const U8 media_flags);
S32 setGlow(const U8 index, const F32 glow);
S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID);
- S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
+ S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
LLMaterialPtr getMaterialParams(const U8 index);
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 284dfc15f4..6020031099 100755
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -63,6 +63,7 @@ LLTextureEntry::LLTextureEntry()
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
@@ -71,6 +72,7 @@ LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
@@ -79,6 +81,7 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
mID = rhs.mID;
mScaleS = rhs.mScaleS;
@@ -562,6 +565,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)
mMaterialUpdatePending = true;
}
mMaterial = pMaterialParams;
+ this->mInitMatParamsFromServer = TRUE;
return TEM_CHANGE_TEXTURE;
}
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index 19edcaa27d..81e2e8a5a2 100755
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -89,6 +89,10 @@ public:
bool operator==(const LLTextureEntry &rhs) const;
bool operator!=(const LLTextureEntry &rhs) const;
+
+ // Added to allow use with std::map
+ //
+ bool operator <(const LLTextureEntry &rhs) const;
LLSD asLLSD() const;
void asLLSD(LLSD& sd) const;
@@ -156,6 +160,8 @@ public:
const LLMaterialID& getMaterialID() const { return mMaterialID; };
const LLMaterialPtr getMaterialParams() const { return mMaterial; };
+ bool isMatParamsInitFromServer() const { return mInitMatParamsFromServer; };
+
// *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.
// CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()
// to NOT return NULL.
@@ -213,6 +219,8 @@ protected:
bool mMaterialUpdatePending;
LLMaterialID mMaterialID;
LLMaterialPtr mMaterial;
+ bool mInitMatParamsFromServer; // Flag to identification when material paramas initialized from
+
// Note the media data is not sent via the same message structure as the rest of the TE
LLMediaEntry* mMediaEntry; // The media data for the face
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index d192aac448..7fb1db15fb 100755
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -282,6 +282,7 @@ target_link_libraries(llui
${LLXML_LIBRARIES}
${LLMATH_LIBRARIES}
${HUNSPELL_LIBRARY}
+ ${LLMESSAGE_LIBRARIES}
${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender
)
@@ -294,5 +295,7 @@ if(LL_TESTS)
LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
# INTEGRATION TESTS
set(test_libs llui llmessage llcorehttp llcommon ${LLCOMMON_LIBRARIES} ${BOOST_COROUTINE_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${WINDOWS_LIBRARIES})
- LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+ if(NOT LINUX)
+ LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+ endif(NOT LINUX)
endif(LL_TESTS)
diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index 3396213f1c..c937d190c6 100755
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -153,7 +153,7 @@ void LLDockableFloater::setVisible(BOOL visible)
mDockControl.get()->repositionDockable();
}
- if (visible)
+ if (visible && !isMinimized())
{
LLFloater::setFrontmost(getAutoFocus());
}
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 81a0204bc5..3def0386e1 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -129,6 +129,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mSelectPending(FALSE),
mLabelStyle( LLFontGL::NORMAL ),
mHasVisibleChildren(FALSE),
+ mIsFolderComplete(true),
mLocalIndentation(p.folder_indentation),
mIndentation(0),
mItemHeight(p.item_height),
@@ -674,7 +675,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
//
const S32 TOP_PAD = default_params.item_top_pad;
- if (hasVisibleChildren())
+ if (hasVisibleChildren() || !isFolderComplete())
{
LLUIImage* arrow_image = default_params.folder_arrow_image;
gl_draw_scaled_rotated_image(
@@ -934,6 +935,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
mLastArrangeGeneration( -1 ),
mLastCalculatedWidth(0)
{
+ // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it.
+ mIsFolderComplete = false;
}
void LLFolderViewFolder::updateLabelRotation()
@@ -1016,6 +1019,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
mHasVisibleChildren = found;
}
+ if (!mIsFolderComplete)
+ {
+ mIsFolderComplete = getFolderViewModel()->isFolderComplete(this);
+ }
+
+
// calculate height as a single item (without any children), and reshapes rectangle to match
LLFolderViewItem::arrange( width, height );
@@ -1463,31 +1472,37 @@ void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection)
LLFolderView* root = getRoot();
- for (std::vector<LLFolderViewItem*>::iterator it = items_to_select_forward.begin(), end_it = items_to_select_forward.end();
+ BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected
+
+ // array always go from 'will be selected' to ' will be unselected', iterate
+ // in opposite direction to simplify identification of 'point of origin' in
+ // case it is in the list we are working with
+ for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend();
it != end_it;
++it)
{
LLFolderViewItem* item = *it;
- if (item->isSelected())
+ BOOL selected = item->isSelected();
+ if (!selection_reverse && selected)
{
- root->removeFromSelectionList(item);
+ // it is our 'point of origin' where we shift/expand from
+ // don't deselect it
+ selection_reverse = TRUE;
}
else
{
- item->selectItem();
+ root->changeSelection(item, !selected);
}
- root->addToSelectionList(item);
}
- if (new_selection->isSelected())
+ if (selection_reverse)
{
- root->removeFromSelectionList(new_selection);
+ // at some point we reversed selection, first element should be deselected
+ root->changeSelection(last_selected_item_from_cur, FALSE);
}
- else
- {
- new_selection->selectItem();
- }
- root->addToSelectionList(new_selection);
+
+ // element we expand to should always be selected
+ root->changeSelection(new_selection, TRUE);
}
@@ -1677,7 +1692,9 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r
mIsOpen = openitem;
if(!was_open && openitem)
{
- getViewModelItem()->openItem();
+ getViewModelItem()->openItem();
+ // openItem() will request content, it won't be incomplete
+ mIsFolderComplete = true;
}
else if(was_open && !openitem)
{
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index ed4496cfaa..0322c8836d 100755
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -115,6 +115,7 @@ protected:
F32 mControlLabelRotation;
LLFolderView* mRoot;
bool mHasVisibleChildren,
+ mIsFolderComplete, // indicates that some children were not loaded/added yet
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
@@ -212,6 +213,9 @@ public:
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
+ // true if object can't have children
+ BOOL isFolderComplete() { return mIsFolderComplete; }
+
// Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed.
//virtual BOOL removeRecursively(BOOL single_item);
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index d60e36183b..a395af537a 100755
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -122,6 +122,7 @@ public:
virtual void filter() = 0;
virtual bool contentsReady() = 0;
+ virtual bool isFolderComplete(class LLFolderViewFolder*) = 0;
virtual void setFolderView(LLFolderView* folder_view) = 0;
virtual LLFolderViewFilter& getFilter() = 0;
virtual const LLFolderViewFilter& getFilter() const = 0;
@@ -444,6 +445,7 @@ public:
// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,
// this method needs to be overloaded and return the relevant fetch status.
virtual bool contentsReady() { return true; }
+ virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; }
struct ViewModelCompare
{
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 7cdbcb0621..848367f8a8 100755
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -225,7 +225,6 @@ BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask)
{
- setHover(TRUE);
getWindow()->setCursor(UI_CURSOR_ARROW);
return TRUE;
}
@@ -236,6 +235,18 @@ BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
return LLUICtrl::handleRightMouseDown(x,y,mask);
}
+void LLMenuItemGL::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ setHover(TRUE);
+ LLUICtrl::onMouseEnter(x,y,mask);
+}
+
+void LLMenuItemGL::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ setHover(FALSE);
+ LLUICtrl::onMouseLeave(x,y,mask);
+}
+
//virtual
BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
{
@@ -533,9 +544,6 @@ void LLMenuItemGL::draw( void )
gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1);
}
}
-
- // clear got hover every frame
- setHover(FALSE);
}
BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& text )
@@ -1043,7 +1051,7 @@ void LLMenuItemBranchGL::onCommit( void )
// keyboard navigation automatically propagates highlight to sub-menu
// to facilitate fast menu control via jump keys
- if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem())
+ if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem())
{
getBranch()->highlightNextItem(NULL);
}
@@ -1456,7 +1464,16 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
{
// switch to mouse control mode
LLMenuGL::setKeyboardMode(FALSE);
- onCommit();
+
+ if (getVisible() && isOpen())
+ {
+ LLMenuGL::sMenuContainer->hideMenus();
+ }
+ else
+ {
+ onCommit();
+ }
+
make_ui_sound("UISndClick");
return TRUE;
}
@@ -1588,10 +1605,6 @@ void LLMenuItemBranchDownGL::draw( void )
gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS);
}
}
-
- // reset every frame so that we only show highlight
- // when we get hover events on that frame
- setHover(FALSE);
}
@@ -3381,6 +3394,11 @@ BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask)
return LLMenuGL::handleMouseDown(x, y, mask);
}
+BOOL LLMenuBarGL::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ return LLMenuGL::handleMouseDown(x, y, mask);
+}
+
void LLMenuBarGL::draw()
{
LLMenuItemGL* itemp = getHighlightedItem();
@@ -3625,8 +3643,24 @@ BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
if (!handled)
{
- // clicked off of menu, hide them all
- hideMenus();
+ LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu();
+ LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL;
+ if (parent_menu && parent_menu->getVisible())
+ {
+ // don't hide menu if parent was hit
+ LLRect parent_rect;
+ parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this);
+ if (!parent_rect.pointInRect(x, y))
+ {
+ // clicked off of menu and parent, hide them all
+ hideMenus();
+ }
+ }
+ else
+ {
+ // no visible parent, clicked off of menu, hide them all
+ hideMenus();
+ }
}
return handled;
}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index ae9b169691..628dedb906 100755
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -158,6 +158,10 @@ public:
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+
+ virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+ virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
virtual void draw( void );
BOOL getHover() const { return mGotHover; }
@@ -753,6 +757,7 @@ public:
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ BOOL handleJumpKey(KEY key);
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ void draw();
/*virtual*/ BOOL jumpKeysActive();
diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp
index ea96fc573d..1fdd05a11c 100755
--- a/indra/llui/llsearcheditor.cpp
+++ b/indra/llui/llsearcheditor.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llsearcheditor.h"
+#include "llkeyboard.h"
LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
: LLUICtrl(p),
@@ -166,4 +167,16 @@ void LLSearchEditor::handleKeystroke()
{
mKeystrokeCallback(this, getValue());
}
+
+ KEY key = gKeyboard->currentKey();
+ if (key == KEY_LEFT ||
+ key == KEY_RIGHT)
+ {
+ return;
+ }
+
+ if (mTextChangedCallback)
+ {
+ mTextChangedCallback(this, getValue());
+ }
}
diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h
index c2d7916938..3b12868225 100755
--- a/indra/llui/llsearcheditor.h
+++ b/indra/llui/llsearcheditor.h
@@ -82,12 +82,14 @@ public:
virtual void setFocus( BOOL b );
void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; }
+ void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
protected:
void onClearButtonClick(const LLSD& data);
virtual void handleKeystroke();
commit_callback_t mKeystrokeCallback;
+ commit_callback_t mTextChangedCallback;
LLLineEditor* mSearchEditor;
LLButton* mSearchButton;
LLButton* mClearButton;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 602a703450..bf660849c4 100755
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -37,6 +37,7 @@
#include "lltextparser.h"
#include "lltextutil.h"
#include "lltooltip.h"
+#include "lltrans.h"
#include "lluictrl.h"
#include "llurlaction.h"
#include "llurlregistry.h"
@@ -2060,27 +2061,33 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
// add icon before url if need
LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted());
+ if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() )
+ {
+ setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon"));
+ }
// output the styled Url
appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
+ bool tooltip_required = !match.getTooltip().empty();
+
+ // set the tooltip for the Url label
+ if (tooltip_required)
+ {
+ setLastSegmentToolTip(match.getTooltip());
+ }
- // show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries
+ // show query part of url with gray color only for LLUrlEntryHTTP url entries
std::string label = match.getQuery();
if (label.size())
{
link_params.color = LLColor4::grey;
link_params.readonly_color = LLColor4::grey;
appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly());
- }
-
- // set the tooltip for the Url label
- if (! match.getTooltip().empty())
- {
- segment_set_t::iterator it = getSegIterContaining(getLength()-1);
- if (it != mSegments.end())
+
+ // set the tooltip for the query part of url
+ if (tooltip_required)
{
- LLTextSegmentPtr segment = *it;
- segment->setToolTip(match.getTooltip());
+ setLastSegmentToolTip(match.getTooltip());
}
}
@@ -2107,6 +2114,16 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
}
}
+void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
+{
+ segment_set_t::iterator it = getSegIterContaining(getLength()-1);
+ if (it != mSegments.end())
+ {
+ LLTextSegmentPtr segment = *it;
+ segment->setToolTip(tooltip);
+ }
+}
+
static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text");
void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
@@ -3557,6 +3574,22 @@ S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
return 0;
}
+BOOL LLImageTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ if (!mTooltip.empty())
+ {
+ LLToolTipMgr::instance().show(mTooltip);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLImageTextSegment::setToolTip(const std::string& tooltip)
+{
+ mTooltip = tooltip;
+}
+
F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
{
if ( (start >= 0) && (end <= mEnd - mStart))
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index dfc10923f3..87809aa8fb 100755
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -241,9 +241,15 @@ public:
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+ /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+ /*virtual*/ void setToolTip(const std::string& tooltip);
+
private:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
+
+protected:
+ std::string mTooltip;
};
typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
@@ -392,6 +398,8 @@ public:
const std::string& getLabel() { return mLabel.getString(); }
const LLWString& getWlabel() { return mLabel.getWString();}
+ void setLastSegmentToolTip(const std::string &tooltip);
+
/**
* If label is set, draws text label (which is LLLabelTextSegment)
* that is visible when no user text provided
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index e76f2a1550..18e43508df 100755
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -203,10 +203,10 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const
{
LLUriParser up(unescapeUrl(url));
- std::string query;
+ std::string label;
up.extractParts();
- up.glueSecond(query);
-
+ up.glueFirst(label);
+ std::string query = url.substr(label.size());
return query;
}
@@ -229,7 +229,7 @@ static std::string getStringAfterToken(const std::string str, const std::string
LLUrlEntryHTTP::LLUrlEntryHTTP()
: LLUrlEntryBase()
{
- mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",
+ mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?\\.[a-z](:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
@@ -287,46 +287,6 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
return getUrlFromWikiLink(string);
}
-//
-// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
-//
-LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol()
- : LLUrlEntryBase()
-{
- mPattern = boost::regex("("
- "\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR
- "|" // or
- "(?<!@)\\b[^[:space:]:@/>]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net
- ")",
- boost::regex::perl|boost::regex::icase);
- mMenuName = "menu_url_http.xml";
- mTooltip = LLTrans::getString("TooltipHttpUrl");
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
-{
- return urlToLabelWithGreyQuery(url);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const
-{
- return urlToGreyQuery(url);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const
-{
- if (string.find("://") == std::string::npos)
- {
- return "http://" + escapeUrl(string);
- }
- return escapeUrl(string);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const
-{
- return unescapeUrl(url);
-}
-
LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL()
: LLUrlEntryBase()
{
@@ -489,7 +449,7 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
//
LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL()
{
- mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*",
+ mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
@@ -527,7 +487,7 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const
//
LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
{
- mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
+ mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
@@ -1401,9 +1361,43 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)
return mIcon;
}
+//
+// LLUrlEntryEmail Describes a generic mailto: Urls
+//
+LLUrlEntryEmail::LLUrlEntryEmail()
+ : LLUrlEntryBase()
+{
+ mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,6}",
+ boost::regex::perl | boost::regex::icase);
+ mMenuName = "menu_url_email.xml";
+ mTooltip = LLTrans::getString("TooltipEmail");
+}
+
+std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ int pos = url.find("mailto:");
+
+ if (pos == std::string::npos)
+ {
+ return escapeUrl(url);
+ }
+
+ std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8));
+ return ret;
+}
+
+std::string LLUrlEntryEmail::getUrl(const std::string &string) const
+{
+ if (string.find("mailto:") == std::string::npos)
+ {
+ return "mailto:" + escapeUrl(string);
+ }
+ return escapeUrl(string);
+}
+
LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*",
+ mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/profile",
boost::regex::perl|boost::regex::icase);
mIcon = "Generic_Experience";
mMenuName = "menu_url_experience.xml";
@@ -1430,7 +1424,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
return LLTrans::getString("ExperienceNameNull");
}
- const LLSD& experience_details = LLExperienceCache::getInstance()->get(experience_id);
+ const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
if(!experience_details.isUndefined())
{
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
@@ -1438,7 +1432,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
}
addObserver(experience_id_string, url, cb);
- LLExperienceCache::getInstance()->get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
+ LLExperienceCache::instance().get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
return LLTrans::getString("LoadingData");
}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index dd1f257a3d..413c20a657 100755
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -157,19 +157,6 @@ public:
/*virtual*/ std::string getUrl(const std::string &string) const;
};
-///
-/// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
-///
-class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase
-{
-public:
- LLUrlEntryHTTPNoProtocol();
- /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
- /*virtual*/ std::string getQuery(const std::string &url) const;
- /*virtual*/ std::string getUrl(const std::string &string) const;
- /*virtual*/ std::string getTooltip(const std::string &url) const;
-};
-
class LLUrlEntryInvalidSLURL : public LLUrlEntryBase
{
public:
@@ -506,5 +493,16 @@ public:
/*virtual*/ std::string getIcon(const std::string &url);
};
+///
+/// LLUrlEntryEmail Describes a generic mailto: Urls
+///
+class LLUrlEntryEmail : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryEmail();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getUrl(const std::string &string) const;
+};
+
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 2085505947..69eefa736c 100755
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -76,9 +76,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntrySL());
mUrlEntrySLLabel = new LLUrlEntrySLLabel();
registerUrl(mUrlEntrySLLabel);
- // most common pattern is a URL without any protocol,
- // e.g., "secondlife.com"
- registerUrl(new LLUrlEntryHTTPNoProtocol());
+ registerUrl(new LLUrlEntryEmail());
}
LLUrlRegistry::~LLUrlRegistry()
@@ -155,11 +153,9 @@ static bool stringHasUrl(const std::string &text)
return (text.find("://") != std::string::npos ||
text.find("www.") != std::string::npos ||
text.find(".com") != std::string::npos ||
- text.find(".net") != std::string::npos ||
- text.find(".edu") != std::string::npos ||
- text.find(".org") != std::string::npos ||
text.find("<nolink>") != std::string::npos ||
- text.find("<icon") != std::string::npos);
+ text.find("<icon") != std::string::npos ||
+ text.find("@") != std::string::npos);
}
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted)
@@ -218,9 +214,40 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
// did we find a match? if so, return its details in the match object
if (match_entry)
{
+
+ // Skip if link is an email with an empty username (starting with @). See MAINT-5371.
+ if (match_start > 0 && text.substr(match_start - 1, 1) == "@")
+ return false;
+
// fill in the LLUrlMatch object and return it
std::string url = text.substr(match_start, match_end - match_start + 1);
+ LLUrlEntryBase *stripped_entry = NULL;
+ if(LLStringUtil::containsNonprintable(url))
+ {
+ LLStringUtil::stripNonprintable(url);
+
+ std::vector<LLUrlEntryBase *>::iterator iter;
+ for (iter = mUrlEntry.begin(); iter != mUrlEntry.end(); ++iter)
+ {
+ LLUrlEntryBase *url_entry = *iter;
+ U32 start = 0, end = 0;
+ if (matchRegex(url.c_str(), url_entry->getPattern(), start, end))
+ {
+ if (mLLUrlEntryInvalidSLURL == *iter)
+ {
+ if(url_entry && url_entry->isSLURLvalid(url))
+ {
+ continue;
+ }
+ }
+ stripped_entry = url_entry;
+ break;
+ }
+ }
+ }
+
+
if (match_entry == mUrlEntryTrusted)
{
LLUriParser up(url);
@@ -228,10 +255,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
url = up.normalizedUri();
}
+ std::string url_label = stripped_entry? stripped_entry->getLabel(url, cb) : match_entry->getLabel(url, cb);
+ std::string url_query = stripped_entry? stripped_entry->getQuery(url) : match_entry->getQuery(url);
match.setValues(match_start, match_end,
match_entry->getUrl(url),
- match_entry->getLabel(url, cb),
- match_entry->getQuery(url),
+ url_label,
+ url_query,
match_entry->getTooltip(url),
match_entry->getIcon(url),
match_entry->getStyle(),
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 15f2354552..544f50d15d 100755
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -37,17 +37,17 @@
#include <boost/regex.hpp>
-namespace LLExperienceCache
-{
- const LLSD& get( const LLUUID& key)
- {
- static LLSD boo;
- return boo;
- }
-
- void get( const LLUUID& key, callback_slot_t slot ){}
-
-}
+// namespace LLExperienceCache
+// {
+// const LLSD& get( const LLUUID& key)
+// {
+// static LLSD boo;
+// return boo;
+// }
+//
+// void get( const LLUUID& key, callback_slot_t slot ){}
+//
+// }
typedef std::map<std::string, LLControlGroup*> settings_map_t;
settings_map_t LLUI::sSettingGroups;
@@ -653,79 +653,6 @@ namespace tut
void object::test<11>()
{
//
- // test LLUrlEntryHTTPNoProtocol - general URLs without a protocol
- //
- LLUrlEntryHTTPNoProtocol url;
-
- testRegex("naked .com URL", url,
- "see google.com",
- "http://google.com");
-
- testRegex("naked .org URL", url,
- "see en.wikipedia.org for details",
- "http://en.wikipedia.org");
-
- testRegex("naked .net URL", url,
- "example.net",
- "http://example.net");
-
- testRegex("naked .edu URL (2 instances)", url,
- "MIT web site is at web.mit.edu and also www.mit.edu",
- "http://web.mit.edu");
-
- testRegex("don't match e-mail addresses", url,
- "test@lindenlab.com",
- "");
-
- testRegex(".com URL with path", url,
- "see secondlife.com/status for grid status",
- "http://secondlife.com/status");
-
- testRegex(".com URL with port", url,
- "secondlife.com:80",
- "http://secondlife.com:80");
-
- testRegex(".com URL with port and path", url,
- "see secondlife.com:80/status",
- "http://secondlife.com:80/status");
-
- testRegex("www.*.com URL with port and path", url,
- "see www.secondlife.com:80/status",
- "http://www.secondlife.com:80/status");
-
- testRegex("invalid .com URL [1]", url,
- "..com",
- "");
-
- testRegex("invalid .com URL [2]", url,
- "you.come",
- "");
-
- testRegex("invalid .com URL [3]", url,
- "recommended",
- "");
-
- testRegex("invalid .edu URL", url,
- "hi there scheduled maitenance has begun",
- "");
-
- testRegex("invalid .net URL", url,
- "foo.netty",
- "");
-
- testRegex("XML tags around URL [1]", url,
- "<foo>secondlife.com</foo>",
- "http://secondlife.com");
-
- testRegex("XML tags around URL [2]", url,
- "<foo>secondlife.com/status?bar=1</foo>",
- "http://secondlife.com/status?bar=1");
- }
-
- template<> template<>
- void object::test<12>()
- {
- //
// test LLUrlEntryNoLink - turn off hyperlinking
//
LLUrlEntryNoLink url;
@@ -752,7 +679,7 @@ namespace tut
}
template<> template<>
- void object::test<13>()
+ void object::test<12>()
{
//
// test LLUrlEntryRegion - secondlife:///app/region/<location> URLs
@@ -860,4 +787,101 @@ namespace tut
"secondlife:///app/region/Product%20Engine",
"Product Engine");
}
+
+ template<> template<>
+ void object::test<13>()
+ {
+ //
+ // test LLUrlEntryemail - general emails
+ //
+ LLUrlEntryEmail url;
+
+ // Regex tests.
+ testRegex("match e-mail addresses", url,
+ "test@lindenlab.com",
+ "mailto:test@lindenlab.com");
+
+ testRegex("match e-mail addresses with mailto: prefix", url,
+ "mailto:test@lindenlab.com",
+ "mailto:test@lindenlab.com");
+
+ testRegex("match e-mail addresses with different domains", url,
+ "test@foo.org.us",
+ "mailto:test@foo.org.us");
+
+ testRegex("match e-mail addresses with different domains", url,
+ "test@foo.bar",
+ "mailto:test@foo.bar");
+
+ testRegex("don't match incorrect e-mail addresses", url,
+ "test @foo.com",
+ "");
+
+ testRegex("don't match incorrect e-mail addresses", url,
+ "test@ foo.com",
+ "");
+ }
+
+ template<> template<>
+ void object::test<14>()
+ {
+ //
+ // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls
+ //
+ LLUrlEntrySecondlifeURL url;
+
+ testRegex("match urls with protocol", url,
+ "this url should match http://lindenlab.com/products/second-life",
+ "http://lindenlab.com/products/second-life");
+
+ testRegex("match urls with protocol", url,
+ "search something https://marketplace.secondlife.com/products/search on marketplace and test the https",
+ "https://marketplace.secondlife.com/products/search");
+
+ testRegex("match urls with port", url,
+ "let's specify some port http://secondlife.com:888/status",
+ "http://secondlife.com:888/status");
+
+ testRegex("don't match urls w/o protocol", url,
+ "looks like an url something www.marketplace.secondlife.com/products but no https prefix",
+ "");
+
+ testRegex("but with a protocol www is fine", url,
+ "so let's add a protocol http://www.marketplace.secondlife.com:8888/products",
+ "http://www.marketplace.secondlife.com:8888/products");
+
+ testRegex("don't match urls w/o protocol", url,
+ "and even no www something secondlife.com/status",
+ "");
+ }
+
+ template<> template<>
+ void object::test<15>()
+ {
+ //
+ // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls
+ //
+
+ LLUrlEntrySimpleSecondlifeURL url;
+
+ testRegex("match urls with a protocol", url,
+ "this url should match http://lindenlab.com",
+ "http://lindenlab.com");
+
+ testRegex("match urls with a protocol", url,
+ "search something https://marketplace.secondlife.com on marketplace and test the https",
+ "https://marketplace.secondlife.com");
+
+ testRegex("don't match urls w/o protocol", url,
+ "looks like an url something www.marketplace.secondlife.com but no https prefix",
+ "");
+
+ testRegex("but with a protocol www is fine", url,
+ "so let's add a protocol http://www.marketplace.secondlife.com",
+ "http://www.marketplace.secondlife.com");
+
+ testRegex("don't match urls w/o protocol", url,
+ "and even no www something lindenlab.com",
+ "");
+ }
}
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index 1c9160a42d..deb8cb90d8 100644
--- a/indra/llwindow/llopenglview-objc.mm
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -239,7 +239,11 @@ attributedStringInfo getSegments(NSAttributedString *str)
{
[glContext setValues:(const GLint*)1 forParameter:NSOpenGLCPSwapInterval];
} else {
- [glContext setValues:(const GLint*)0 forParameter:NSOpenGLCPSwapInterval];
+ // supress this error after move to Xcode 7:
+ // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull]
+ // Tried using ObjC 'nonnull' keyword as per SO article but didn't build
+ GLint swapInterval=0;
+ [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
}
mOldResize = false;
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 5720660034..1b24250618 100755
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -49,8 +49,8 @@ LLSplashScreen *gSplashScreenp = NULL;
BOOL gDebugClicks = FALSE;
BOOL gDebugWindowProc = FALSE;
-const S32 gURLProtocolWhitelistCount = 4;
-const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:" };
+const S32 gURLProtocolWhitelistCount = 5;
+const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" };
// CP: added a handler list - this is what's used to open the protocol and is based on registry entry
// only meaningful difference currently is that file: protocols are opened using http:
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index f02052ca6a..e6e8f27f53 100755
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -53,6 +53,7 @@ bool runMainLoop();
void initMainLoop();
void cleanupViewer();
void handleUrl(const char* url);
+void dispatchUrl(std::string url);
/* Defined in llwindowmacosx-objc.mm: */
int createNSApp(int argc, const char **argv);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 090879e372..feb2e207fe 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -138,7 +138,6 @@ set(viewer_SOURCE_FILES
llbreadcrumbview.cpp
llbrowsernotification.cpp
llbuycurrencyhtml.cpp
- llcallbacklist.cpp
llcallingcard.cpp
llchannelmanager.cpp
llchatbar.cpp
@@ -192,7 +191,6 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
- llexperienceassociationresponder.cpp
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
@@ -269,9 +267,9 @@ set(viewer_SOURCE_FILES
llfloatermodeluploadbase.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
+ llfloaternotificationstabbed.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
- llfloateroutbox.cpp
llfloaterpathfindingcharacters.cpp
llfloaterpathfindingconsole.cpp
llfloaterpathfindinglinksets.cpp
@@ -402,6 +400,8 @@ set(viewer_SOURCE_FILES
llnotificationgrouphandler.cpp
llnotificationhandlerutil.cpp
llnotificationhinthandler.cpp
+ llnotificationlistitem.cpp
+ llnotificationlistview.cpp
llnotificationmanager.cpp
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
@@ -562,7 +562,6 @@ set(viewer_SOURCE_FILES
lltextureinfo.cpp
lltextureinfodetails.cpp
lltexturestats.cpp
- lltexturestatsuploader.cpp
lltextureview.cpp
lltoast.cpp
lltoastalertpanel.cpp
@@ -746,7 +745,6 @@ set(viewer_HEADER_FILES
llbox.h
llbreadcrumbview.h
llbuycurrencyhtml.h
- llcallbacklist.h
llcallingcard.h
llcapabilityprovider.h
llchannelmanager.h
@@ -801,7 +799,6 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
- llexperienceassociationresponder.h
llexperiencelog.h
llexternaleditor.h
llface.h
@@ -881,9 +878,9 @@ set(viewer_HEADER_FILES
llfloatermodeluploadbase.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
+ llfloaternotificationstabbed.h
llfloaterobjectweights.h
llfloateropenobject.h
- llfloateroutbox.h
llfloaterpathfindingcharacters.h
llfloaterpathfindingconsole.h
llfloaterpathfindinglinksets.h
@@ -1007,6 +1004,8 @@ set(viewer_HEADER_FILES
llnavigationbar.h
llnetmap.h
llnotificationhandler.h
+ llnotificationlistitem.h
+ llnotificationlistview.h
llnotificationmanager.h
llnotificationstorage.h
lloutfitslist.h
@@ -1162,7 +1161,6 @@ set(viewer_HEADER_FILES
lltextureinfo.h
lltextureinfodetails.h
lltexturestats.h
- lltexturestatsuploader.h
lltextureview.h
lltoast.h
lltoastalertpanel.h
@@ -2228,7 +2226,6 @@ if (LL_TESTS)
# llmediadataclient.cpp
lllogininstance.cpp
# llremoteparcelrequest.cpp
- lltranslate.cpp
llviewerhelputil.cpp
llversioninfo.cpp
llworldmap.cpp
@@ -2250,12 +2247,6 @@ if (LL_TESTS)
)
set_source_files_properties(
- lltranslate.cpp
- PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"
- )
-
- set_source_files_properties(
llmediadataclient.cpp
PROPERTIES
LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"
@@ -2388,7 +2379,6 @@ if (LL_TESTS)
#ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
- #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
include(LLAddBuildTest)
SET(viewer_TEST_SOURCE_FILES
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index ff313b8c21..4351a7e3a3 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.8.4
+3.8.7
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ee1d491073..2ca090b179 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2,6 +2,39 @@
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="llsd.xsd">
<map>
+ <key>ImporterDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ImporterLegacyMatching</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable index based model matching.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ImporterModelLimit</key>
+ <map>
+ <key>Comment</key>
+ <string>Limits amount of importer generated models for dae files</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>768</integer>
+ </map>
<key>IMShowTime</key>
<map>
<key>Comment</key>
@@ -14189,7 +14222,7 @@
<key>MaxFPS</key>
<map>
<key>Comment</key>
- <string>Yield some time to the local host if we reach a threshold framerate.</string>
+ <string>OBSOLETE UNUSED setting.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
index 6cd38d8ef5..3060307b21 100755
--- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
@@ -37,8 +37,7 @@ mat4 getObjectSkinnedTransform()
index = min(index, vec4(51.0));
index = max(index, vec4( 0.0));
- float scale = 1.0/(w.x+w.y+w.z+w.w);
- w *= scale;
+ w *= 1.0/(w.x+w.y+w.z+w.w);
int i1 = int(index.x);
int i2 = int(index.y);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 595c11fae2..58fb01d200 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -29,6 +29,7 @@ out vec4 frag_data[3];
#define frag_data gl_FragData
#endif
+uniform float minimum_alpha;
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
@@ -47,16 +48,23 @@ vec2 encode_normal(vec3 n)
void main()
{
- vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
- vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
+ vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
+
+ if(col.a < minimum_alpha)
+ {
+ discard;
+ }
+ col *= vertex_color;
+
+ vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
- vec3 tnorm = vec3(dot(norm,vary_mat0),
+ vec3 tnorm = vec3(dot(norm,vary_mat0),
dot(norm,vary_mat1),
dot(norm,vary_mat2));
- frag_data[0] = vec4(col, 0.0);
- frag_data[1] = vertex_color.aaaa; // spec
- //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
- vec3 nvn = normalize(tnorm);
- frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
+ frag_data[0] = vec4(col.rgb, 0.0);
+ frag_data[1] = vertex_color.aaaa; // spec
+ //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
+ vec3 nvn = normalize(tnorm);
+ frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0);
}
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 95cdf90e99..b8677fd9e4 100755
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -165,7 +165,9 @@ lbl_configure_default_lang:
StrCpy $LANGUAGE $0
# For silent installs, no language prompt, use default
- IfSilent lbl_return
+ IfSilent 0 +3
+ StrCpy $SKIP_AUTORUN "true"
+ Goto lbl_return
StrCmp $SKIP_DIALOGS "true" lbl_return
lbl_build_menu:
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index cd9146ea16..92a5413adb 100755
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -31,14 +31,12 @@
#include "llcoros.h"
#include "lleventcoro.h"
#include "llcorehttputil.h"
+#include <algorithm>
+#include <iterator>
//===============================================================================
-LLAccountingCostManager::LLAccountingCostManager():
- mHttpRequest(),
- mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)
+LLAccountingCostManager::LLAccountingCostManager()
{
- mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
- //mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
}
@@ -51,30 +49,24 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName()
<< " with url '" << url << LL_ENDL;
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AccountingCost", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
try
{
- LLSD objectList;
- U32 objectIndex = 0;
+ uuid_set_t diffSet;
- IDIt IDIter = mObjectList.begin();
- IDIt IDIterEnd = mObjectList.end();
+ std::set_difference(mObjectList.begin(), mObjectList.end(),
+ mPendingObjectQuota.begin(), mPendingObjectQuota.end(),
+ std::inserter(diffSet, diffSet.begin()));
- for (; IDIter != IDIterEnd; ++IDIter)
- {
- // Check to see if a request for this object has already been made.
- if (mPendingObjectQuota.find(*IDIter) == mPendingObjectQuota.end())
- {
- mPendingObjectQuota.insert(*IDIter);
- objectList[objectIndex++] = *IDIter;
- }
- }
+ if (diffSet.empty())
+ return;
mObjectList.clear();
- //Post results
- if (objectList.size() == 0)
- return;
-
std::string keystr;
if (selectionType == Roots)
{
@@ -87,11 +79,18 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
else
{
LL_INFOS() << "Invalid selection type " << LL_ENDL;
- mObjectList.clear();
- mPendingObjectQuota.clear();
return;
}
+ LLSD objectList(LLSD::emptyMap());
+
+ for (uuid_set_t::iterator it = diffSet.begin(); it != diffSet.end(); ++it)
+ {
+ objectList.append(*it);
+ }
+
+ mPendingObjectQuota.insert(diffSet.begin(), diffSet.end());
+
LLSD dataToPost = LLSD::emptyMap();
dataToPost[keystr.c_str()] = objectList;
@@ -99,27 +98,27 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
LLUUID transactionId = observer->getTransactionID();
observer = NULL;
- LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("AccountingCost", mHttpPolicy);
- LLSD results = httpAdapter.postAndYield(mHttpRequest, url, dataToPost);
- LLSD httpResults;
- httpResults = results["http_result"];
+ LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost);
+
+ LLSD httpResults = results["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
// do/while(false) allows error conditions to break out of following
// block while normal flow goes forward once.
do
{
observer = observerHandle.get();
- if ((!observer) || (observer->getTransactionID() != transactionId))
- { // *TODO: Rider: I've noticed that getTransactionID() does not
- // always match transactionId (the new transaction Id does not show a
- // corresponding request.) (ask Vir)
- if (!observer)
- break;
- LL_WARNS() << "Request transaction Id(" << transactionId
- << ") does not match observer's transaction Id("
- << observer->getTransactionID() << ")." << LL_ENDL;
+
+ if (!status || results.has("error"))
+ {
+ LL_WARNS() << "Error on fetched data" << LL_ENDL;
+ if (!status)
+ observer->setErrorStatus(status.getType(), status.toString());
+ else
+ observer->setErrorStatus(499, "Error on fetched data");
+
break;
}
@@ -134,22 +133,18 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
break;
}
- if (!results.isMap() || results.has("error"))
- {
- LL_WARNS() << "Error on fetched data" << LL_ENDL;
- observer->setErrorStatus(499, "Error on fetched data");
- break;
- }
if (results.has("selected"))
{
+ LLSD selected = results["selected"];
+
F32 physicsCost = 0.0f;
F32 networkCost = 0.0f;
F32 simulationCost = 0.0f;
- physicsCost = results["selected"]["physics"].asReal();
- networkCost = results["selected"]["streaming"].asReal();
- simulationCost = results["selected"]["simulation"].asReal();
+ physicsCost = selected["physics"].asReal();
+ networkCost = selected["streaming"].asReal();
+ simulationCost = selected["simulation"].asReal();
SelectionCost selectionCost( physicsCost, networkCost, simulationCost);
diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h
index d5a94f6fda..f251ceffd4 100755
--- a/indra/newview/llaccountingcostmanager.h
+++ b/indra/newview/llaccountingcostmanager.h
@@ -71,16 +71,13 @@ public:
private:
//Set of objects that will be used to generate a cost
- std::set<LLUUID> mObjectList;
+ uuid_set_t mObjectList;
//During fetchCosts we move object into a the pending set to signify that
//a fetch has been instigated.
- std::set<LLUUID> mPendingObjectQuota;
- typedef std::set<LLUUID>::iterator IDIt;
+ uuid_set_t mPendingObjectQuota;
void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
- LLCore::HttpRequest::ptr_t mHttpRequest;
- LLCore::HttpRequest::policy_t mHttpPolicy;
};
//===============================================================================
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 3316f1e654..e33d34ebc7 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2829,7 +2829,7 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */
// This implementation should mirror LLAgentInfo::hasPowerInGroup
BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
{
- if (isGodlike())
+ if (isGodlikeWithoutAdminMenuFakery())
return true;
// GP_NO_POWERS can also mean no power is enough to grant an ability.
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 5731f4db89..d46973ddee 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -36,6 +36,7 @@
#include "llpermissionsflags.h"
#include "llevents.h"
#include "v3dmath.h"
+#include "httprequest.h"
#include "llcorehttputil.h"
#include <boost/function.hpp>
@@ -935,6 +936,8 @@ public:
bool requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL);
bool requestGetCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL);
+ LLCore::HttpRequest::policy_t getAgentPolicy() const { return mHttpPolicy; }
+
/** Utility
** **
*******************************************************************************/
diff --git a/indra/newview/llagentdata.cpp b/indra/newview/llagentdata.cpp
index 5f6a082d75..d2c644a06f 100755
--- a/indra/newview/llagentdata.cpp
+++ b/indra/newview/llagentdata.cpp
@@ -31,3 +31,4 @@
LLUUID gAgentID;
LLUUID gAgentSessionID;
+std::string gAgentUsername;
diff --git a/indra/newview/llagentdata.h b/indra/newview/llagentdata.h
index 83d6a53d5e..efdd97f6c4 100755
--- a/indra/newview/llagentdata.h
+++ b/indra/newview/llagentdata.h
@@ -30,5 +30,6 @@
extern LLUUID gAgentID;
extern LLUUID gAgentSessionID;
+extern std::string gAgentUsername;
#endif
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index da2f69126a..afc6e208e6 100755
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -99,7 +99,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
// I may be suffering from golden hammer here, but the first part of this bind
- // is actually a static cast for &HttpCoroutineAdapter::postAndYield so that
+ // is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that
// the compiler can identify the correct signature to select.
//
// Reads as follows:
@@ -117,7 +117,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndYield), _1, _2, _3, _4, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
@@ -150,7 +150,7 @@ void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, comple
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndYield), _1, _2, _3, _4, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, putFn, url, folderId, newInventory, callback, SLAMFOLDER));
@@ -182,7 +182,7 @@ void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback)
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, delFn, url, categoryId, LLSD(), callback, REMOVECATEGORY));
@@ -215,7 +215,7 @@ void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback)
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, delFn, url, itemId, LLSD(), callback, REMOVEITEM));
@@ -258,7 +258,7 @@ void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, b
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::copyAndYield), _1, _2, _3, destination, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::copyAndSuspend), _1, _2, _3, destination, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, copyFn, url, destId, LLSD(), callback, COPYLIBRARYCATEGORY));
@@ -291,7 +291,7 @@ void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback)
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, delFn, url, categoryId, LLSD(), callback, PURGEDESCENDENTS));
@@ -323,7 +323,7 @@ void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, compl
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndYield), _1, _2, _3, _4, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, patchFn, url, categoryId, updates, callback, UPDATECATEGORY));
@@ -355,7 +355,7 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndYield), _1, _2, _3, _4, _5, _6);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, patchFn, url, itemId, updates, callback, UPDATEITEM));
@@ -367,7 +367,7 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
{
std::string procFullName = "AIS(" + procName + ")";
- LLCoprocedureManager::getInstance()->enqueueCoprocedure("AIS", procFullName, proc);
+ LLCoprocedureManager::instance().enqueueCoprocedure("AIS", procFullName, proc);
}
@@ -380,7 +380,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
LLCore::HttpHeaders::ptr_t httpHeaders;
- httpOptions->setTimeout(HTTP_REQUEST_EXPIRY_SECS);
+ httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 2de8003c2f..e97059014b 100755
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -31,8 +31,6 @@
#include <map>
#include <set>
#include <string>
-#include "llcurl.h"
-#include "llhttpclient.h"
#include "llhttpretrypolicy.h"
#include "llviewerinventory.h"
#include "llcorehttputil.h"
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index 51cca273d8..8c276c0fe9 100755
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -138,6 +138,9 @@ LLAppCoreHttp::~LLAppCoreHttp()
void LLAppCoreHttp::init()
{
+
+ LLCore::LLHttp::initialize();
+
LLCore::HttpStatus status = LLCore::HttpRequest::createService();
if (! status)
{
@@ -275,12 +278,25 @@ void setting_changed()
LLAppViewer::instance()->getAppCoreHttp().refreshSettings(false);
}
+namespace
+{
+ // The NoOpDeletor is used when wrapping LLAppCoreHttp in a smart pointer below for
+ // passage into the LLCore::Http libararies. When the smart pointer is destroyed,
+ // no action will be taken since we do not in this case want the entire LLAppCoreHttp object
+ // to be destroyed at the end of the call.
+ //
+ // *NOTE$: Yes! It is "Deletor"
+ // http://english.stackexchange.com/questions/4733/what-s-the-rule-for-adding-er-vs-or-when-nouning-a-verb
+ // "delete" derives from Latin "deletus"
+ void NoOpDeletor(LLCore::HttpHandler *)
+ { /*NoOp*/ }
+}
void LLAppCoreHttp::requestStop()
{
llassert_always(mRequest);
- mStopHandle = mRequest->requestStopThread(this);
+ mStopHandle = mRequest->requestStopThread(LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
if (LLCORE_HTTP_HANDLE_INVALID != mStopHandle)
{
mStopRequested = LLTimer::getTotalSeconds();
@@ -393,7 +409,7 @@ void LLAppCoreHttp::refreshSettings(bool initial)
handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_PIPELINING_DEPTH,
mHttpClasses[app_policy].mPolicy,
new_depth,
- NULL);
+ LLCore::HttpHandler::ptr_t());
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
status = mRequest->getStatus();
@@ -443,7 +459,7 @@ void LLAppCoreHttp::refreshSettings(bool initial)
handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
mHttpClasses[app_policy].mPolicy,
(mHttpClasses[app_policy].mPipelined ? 2 * setting : setting),
- NULL);
+ LLCore::HttpHandler::ptr_t());
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
status = mRequest->getStatus();
@@ -456,7 +472,7 @@ void LLAppCoreHttp::refreshSettings(bool initial)
handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_PER_HOST_CONNECTION_LIMIT,
mHttpClasses[app_policy].mPolicy,
setting,
- NULL);
+ LLCore::HttpHandler::ptr_t());
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
status = mRequest->getStatus();
@@ -483,7 +499,7 @@ void LLAppCoreHttp::refreshSettings(bool initial)
}
LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,
- LLCore::HttpHandler const * const handler, void *appdata)
+ const LLCore::HttpHandler::ptr_t &handler, void *appdata)
{
X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
LLCore::HttpStatus result;
diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h
index 410d7c6b07..95c138d598 100755
--- a/indra/newview/llappcorehttp.h
+++ b/indra/newview/llappcorehttp.h
@@ -257,7 +257,7 @@ private:
bool mPipelined; // Global setting
boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting
- static LLCore::HttpStatus sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata);
+ static LLCore::HttpStatus sslVerify(const std::string &uri, const LLCore::HttpHandler::ptr_t &handler, void *appdata);
};
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index eea585e998..d080dfb66e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -57,6 +57,8 @@
#include "llhttpsdhandler.h"
#include "llcorehttputil.h"
#include "llappviewer.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -1885,6 +1887,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)
{
++n_clothes;
}
+ else if (item->getType() == LLAssetType::AT_BODYPART)
+ {
+ return isAgentAvatarValid();
+ }
else
{
LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
@@ -3348,84 +3354,123 @@ LLSD LLAppearanceMgr::dumpCOF() const
void LLAppearanceMgr::requestServerAppearanceUpdate()
{
+ LLCoros::instance().launch("LLAppearanceMgr::serverAppearanceUpdateCoro",
+ boost::bind(&LLAppearanceMgr::serverAppearanceUpdateCoro, this));
+}
- if (!testCOFRequestVersion())
- {
- // *TODO: LL_LOG message here
- return;
- }
+void LLAppearanceMgr::serverAppearanceUpdateCoro()
+{
+ // If we have already received an update for this or higher cof version, ignore.
+ S32 cofVersion = getCOFVersion();
+ S32 lastRcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
+ S32 lastReq = gAgentAvatarp->mLastUpdateRequestCOFVersion;
- if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))
- {
- LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
- mInFlightCounter = 0;
- }
+ //----------------
+ // move out of coroutine
+ if (!gAgent.getRegion())
+ {
+ LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL;
+ return;
+ }
+ if (gAgent.getRegion()->getCentralBakeVersion() == 0)
+ {
+ LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;
+ }
- if (gAgentAvatarp->isEditingAppearance())
- {
- LL_WARNS("Avatar") << "Avatar editing appearance, not sending request." << LL_ENDL;
- // don't send out appearance updates if in appearance editing mode
- return;
- }
+ std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
+ if (url.empty())
+ {
+ LL_WARNS("Agent") << "Could not retrieve region capability \"UpdateAvatarAppearance\"" << LL_ENDL;
+ }
- if (!gAgent.getRegion())
- {
- LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL;
- return;
- }
- if (gAgent.getRegion()->getCentralBakeVersion() == 0)
- {
- LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;
- }
+ //----------------
+ if (gAgentAvatarp->isEditingAppearance())
+ {
+ LL_WARNS("Avatar") << "Avatar editing appearance, not sending request." << LL_ENDL;
+ // don't send out appearance updates if in appearance editing mode
+ return;
+ }
- LLSD postData;
- S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
- if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
- {
- postData = LLAppearanceMgr::instance().dumpCOF();
- }
- else
- {
- postData["cof_version"] = cof_version;
- if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
- {
- postData["cof_version"] = cof_version + 999;
- }
- }
+ LL_DEBUGS("Avatar") << "COF version=" << cofVersion <<
+ " last_rcv=" << lastRcv <<
+ " last_req=" << lastReq << LL_ENDL;
+
+ if (cofVersion < lastRcv)
+ {
+ LL_WARNS("Avatar") << "Have already received update for cof version " << lastRcv
+ << " will not request for " << cofVersion << LL_ENDL;
+ return;
+ }
+ if (lastReq >= cofVersion)
+ {
+ LL_WARNS("Avatar") << "Request already in flight for cof version " << lastReq
+ << " will not request for " << cofVersion << LL_ENDL;
+ return;
+ }
- mInFlightCounter++;
- mInFlightTimer.setTimerExpirySec(60.0);
+ // Actually send the request.
+ LL_DEBUGS("Avatar") << "Will send request for cof_version " << cofVersion << LL_ENDL;
- llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
- gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter(
+ "UpdateAvatarAppearance", gAgent.getAgentPolicy()));
- if (!gAgent.requestPostCapability("UpdateAvatarAppearance", postData,
- static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::serverAppearanceUpdateSuccess, this, _1)),
- static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::decrementInFlightCounter, this))))
+ S32 reqCofVersion = cofVersion;
+ if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
{
- LL_WARNS("Avatar") << "Unable to access UpdateAvatarAppearance in this region." << LL_ENDL;
+ reqCofVersion += 999;
+ LL_WARNS("Avatar") << "Forcing version failure on COF Baking" << LL_ENDL;
}
-}
-void LLAppearanceMgr::serverAppearanceUpdateSuccess(const LLSD &result)
-{
- decrementInFlightCounter();
- if (result["success"].asBoolean())
+ do
{
- LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ LLSD postData;
+ if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
{
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result);
+ postData = dumpCOF();
}
- }
- else
- {
- LL_WARNS("Avatar") << "Non success response for change appearance" << LL_ENDL;
+ else
+ {
+ postData["cof_version"] = reqCofVersion;
+ }
+
+ gAgentAvatarp->mLastUpdateRequestCOFVersion = reqCofVersion;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status || !result["success"].asBoolean())
+ {
+ std::string message = (result.has("error")) ? result["error"].asString() : status.toString();
+ LL_WARNS("Avatar") << "Appearance Failure. server responded with \"" << message << "\"" << LL_ENDL;
+
+ // We may have requested a bake for a stale COF (especially if the inventory
+ // is still updating. If that is the case re send the request with the
+ // corrected COF version. (This may also be the case if the viewer is running
+ // on multiple machines.
+ if (result.has("expected"))
+ {
+ reqCofVersion = result["expected"].asInteger();
+
+ LL_WARNS("Avatar") << "Will Retry with expected COF value of " << reqCofVersion << LL_ENDL;
+ continue;
+ }
+
+ break;
+ }
+
+ LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
- debugAppearanceUpdateCOF(result);
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result);
}
- }
+
+ break;
+ } while (true);
+
}
/*static*/
@@ -3513,36 +3558,6 @@ void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content)
}
-bool LLAppearanceMgr::testCOFRequestVersion() const
-{
- // If we have already received an update for this or higher cof version, ignore.
- S32 cof_version = getCOFVersion();
- S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
- S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion;
-
- LL_DEBUGS("Avatar") << "cof_version " << cof_version
- << " last_rcv " << last_rcv
- << " last_req " << last_req
- << " in flight " << mInFlightCounter
- << LL_ENDL;
- if (cof_version < last_rcv)
- {
- LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
- << " will not request for " << cof_version << LL_ENDL;
- return false;
- }
- if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version)
- {
- LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
- << " will not request for " << cof_version << LL_ENDL;
- return false;
- }
-
- // Actually send the request.
- LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL;
- return true;
-}
-
std::string LLAppearanceMgr::getAppearanceServiceURL() const
{
if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty())
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 9b6ceb7d3e..118648b7c3 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -225,15 +225,9 @@ public:
std::string getAppearanceServiceURL() const;
- bool testCOFRequestVersion() const;
- void decrementInFlightCounter()
- {
- mInFlightCounter = llmax(mInFlightCounter - 1, 0);
- }
-
private:
- void serverAppearanceUpdateSuccess(const LLSD &result);
+ void serverAppearanceUpdateCoro();
static void debugAppearanceUpdateCOF(const LLSD& content);
std::string mAppearanceServiceURL;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e13a9d96c7..564e2450e8 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -57,8 +57,6 @@
#include "llfocusmgr.h"
#include "llviewerjoystick.h"
#include "llallocator.h"
-#include "llares.h"
-#include "llcurl.h"
#include "llcalc.h"
#include "llconversationlog.h"
#include "lldxhardware.h"
@@ -828,12 +826,7 @@ bool LLAppViewer::init()
// before consumers (LLTextureFetch).
mAppCoreHttp.init();
- // *NOTE:Mani - LLCurl::initClass is not thread safe.
- // Called before threads are created.
- LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),
- gSavedSettings.getS32("CurlMaximumNumberOfHandles"),
- gSavedSettings.getBOOL("CurlUseMultipleThreads"));
- LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
+ LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ;
LLMachineID::init();
@@ -903,7 +896,7 @@ bool LLAppViewer::init()
// the libs involved in getting to a full login screen.
//
LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
- LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
+ LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL;
/////////////////////////////////////////////////
// OS-specific login dialogs
@@ -1160,8 +1153,6 @@ bool LLAppViewer::init()
{
LLNotificationsUtil::add("CorruptedProtectedDataStore");
}
- LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
-
gGLActive = FALSE;
@@ -1291,7 +1282,6 @@ static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread");
static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads");
static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle");
static LLTrace::BlockTimerStatHandle FTM_PUMP("Pump");
-static LLTrace::BlockTimerStatHandle FTM_PUMP_ARES("Ares");
static LLTrace::BlockTimerStatHandle FTM_PUMP_SERVICE("Service");
static LLTrace::BlockTimerStatHandle FTM_SERVICE_CALLBACK("Callback");
static LLTrace::BlockTimerStatHandle FTM_AGENT_AUTOPILOT("Autopilot");
@@ -1315,8 +1305,6 @@ bool LLAppViewer::mainLoop()
// Create IO Pump to use for HTTP Requests.
gServicePump = new LLPumpIO(gAPRPoolp);
- LLHTTPClient::setPump(*gServicePump);
- LLCurl::setCAFile(gDirUtilp->getCAFile());
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
@@ -1435,26 +1423,6 @@ bool LLAppViewer::mainLoop()
LL_RECORD_BLOCK_TIME(FTM_IDLE);
idle();
- if (gAres != NULL && gAres->isInitialized())
- {
- pingMainloopTimeout("Main:ServicePump");
- LL_RECORD_BLOCK_TIME(FTM_PUMP);
- {
- LL_RECORD_BLOCK_TIME(FTM_PUMP_ARES);
- gAres->process();
- }
- {
- LL_RECORD_BLOCK_TIME(FTM_PUMP_SERVICE);
- // this pump is necessary to make the login screen show up
- gServicePump->pump();
-
- {
- LL_RECORD_BLOCK_TIME(FTM_SERVICE_CALLBACK);
- gServicePump->callback();
- }
- }
- }
-
resumeMainloopTimeout();
}
@@ -1559,11 +1527,6 @@ bool LLAppViewer::mainLoop()
}
gMeshRepo.update() ;
- if(!LLCurl::getCurlThread()->update(1))
- {
- LLCurl::getCurlThread()->pause() ; //nothing in the curl thread.
- }
-
if(!total_work_pending) //pause texture fetching threads if nothing to process.
{
LLAppViewer::getTextureCache()->pause();
@@ -1801,13 +1764,14 @@ bool LLAppViewer::cleanup()
if (gAudiop)
{
- // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
-
- LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
+ // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it.
+ gAudiop->stopInternetStream();
+ // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
+ LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
delete sai;
gAudiop->setStreamingAudioImpl(NULL);
- // shut down the audio subsystem
+ // shut down the audio subsystem
gAudiop->shutdown();
delete gAudiop;
@@ -2001,7 +1965,6 @@ bool LLAppViewer::cleanup()
pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
pending += LLVFSThread::updateClass(0);
pending += LLLFSThread::updateClass(0);
- pending += LLCurl::getCurlThread()->update(1) ;
F64 idle_time = idleTimer.getElapsedTimeF64();
if(!pending)
{
@@ -2013,7 +1976,6 @@ bool LLAppViewer::cleanup()
break;
}
}
- LLCurl::getCurlThread()->pause() ;
// Delete workers first
// shotdown all worker threads before deleting them in case of co-dependencies
@@ -2028,17 +1990,9 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();
- // *NOTE:Mani - The following call is not thread safe.
- LL_CHECK_MEMORY
- LLCurl::cleanupClass();
- LL_CHECK_MEMORY
-
// Non-LLCurl libcurl library
mAppCoreHttp.cleanup();
- // NOTE The following call is not thread safe.
- ll_cleanup_ares();
-
LLFilePickerThread::cleanupClass();
//MUST happen AFTER LLCurl::cleanupClass
@@ -2124,6 +2078,7 @@ bool LLAppViewer::cleanup()
}
LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL;
LLProxy::cleanupClass();
+ LLCore::LLHttp::cleanup();
LLWearableType::cleanupClass();
@@ -2793,10 +2748,12 @@ bool LLAppViewer::initConfiguration()
//
gWindowTitle = LLTrans::getString("APP_NAME");
#if LL_DEBUG
- gWindowTitle += std::string(" [DEBUG] ") + gArgs;
-#else
- gWindowTitle += std::string(" ") + gArgs;
+ gWindowTitle += std::string(" [DEBUG]")
#endif
+ if (!gArgs.empty())
+ {
+ gWindowTitle += std::string(" ") + gArgs;
+ }
LLStringUtil::truncate(gWindowTitle, 255);
//RN: if we received a URL, hand it off to the existing instance.
@@ -3363,7 +3320,7 @@ LLSD LLAppViewer::getViewerInfo() const
#endif
info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
- info["LIBCURL_VERSION"] = LLCurl::getVersionString();
+ info["LIBCURL_VERSION"] = LLCore::LLHttp::getCURLVersion();
info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
bool want_fullname = true;
info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();
@@ -4931,6 +4888,7 @@ void LLAppViewer::idle()
gIdleCallbacks.callFunctions();
gInventory.idleNotifyObservers();
+ LLAvatarTracker::instance().idleNotifyObservers();
}
// Metrics logging (LLViewerAssetStats, etc.)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 56154a2de3..09227806fd 100755
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -62,9 +62,10 @@ namespace
// They are not used immediately by the app.
int gArgC;
char** gArgV;
- LLAppViewerMacOSX* gViewerAppPtr;
+ LLAppViewerMacOSX* gViewerAppPtr = NULL;
void (*gOldTerminateHandler)() = NULL;
+ std::string gHandleSLURL;
}
static void exceptionTerminateHandler()
@@ -107,7 +108,11 @@ bool initViewer()
{
LL_WARNS() << "Application init failed." << LL_ENDL;
}
-
+ else if (!gHandleSLURL.empty())
+ {
+ dispatchUrl(gHandleSLURL);
+ gHandleSLURL = "";
+ }
return ok;
}
@@ -393,22 +398,31 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute()
void handleUrl(const char* url_utf8)
{
- if (url_utf8)
+ if (url_utf8 && gViewerAppPtr)
{
- std::string url = url_utf8;
- // Safari 3.2 silently mangles secondlife:///app/ URLs into
- // secondlife:/app/ (only one leading slash).
- // Fix them up to meet the URL specification. JC
- const std::string prefix = "secondlife:/app/";
- std::string test_prefix = url.substr(0, prefix.length());
- LLStringUtil::toLower(test_prefix);
- if (test_prefix == prefix)
- {
- url.replace(0, prefix.length(), "secondlife:///app/");
- }
-
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- LLURLDispatcher::dispatch(url, "", web, trusted_browser);
+ gHandleSLURL = "";
+ dispatchUrl(url_utf8);
}
+ else if (url_utf8)
+ {
+ gHandleSLURL = url_utf8;
+ }
+}
+
+void dispatchUrl(std::string url)
+{
+ // Safari 3.2 silently mangles secondlife:///app/ URLs into
+ // secondlife:/app/ (only one leading slash).
+ // Fix them up to meet the URL specification. JC
+ const std::string prefix = "secondlife:/app/";
+ std::string test_prefix = url.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if (test_prefix == prefix)
+ {
+ url.replace(0, prefix.length(), "secondlife:///app/");
+ }
+
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ LLURLDispatcher::dispatch(url, "", web, trusted_browser);
}
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 281e591b48..25a5df9781 100755
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -311,6 +311,7 @@ bool LLAvatarIconCtrl::updateFromCache()
else
{
LLIconCtrl::setValue(mDefaultIconName);
+ return false;
}
return true;
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp
index e260142254..470f516db2 100644
--- a/indra/newview/llavatarrenderinfoaccountant.cpp
+++ b/indra/newview/llavatarrenderinfoaccountant.cpp
@@ -67,7 +67,7 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
if (!regionp)
@@ -190,7 +190,7 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U
report[KEY_AGENTS] = agents;
regionp = NULL;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, report);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, report);
regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
if (!regionp)
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
index 59ecbdd0ea..59ecbdd0ea 100755..100644
--- a/indra/newview/llcallbacklist.cpp
+++ b/indra/newview/llcallbacklist.cpp
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index b6c5496c17..f79d1aa609 100755
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -97,7 +97,8 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id,
LLAvatarTracker::LLAvatarTracker() :
mTrackingData(NULL),
mTrackedAgentValid(false),
- mModifyMask(0x0)
+ mModifyMask(0x0),
+ mIsNotifyObservers(FALSE)
{
}
@@ -272,7 +273,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
<< "]" << LL_ENDL;
}
}
- notifyObservers();
+ // do not notify observers here - list can be large so let it be done on idle.
return new_buddy_count;
}
@@ -473,8 +474,25 @@ void LLAvatarTracker::removeObserver(LLFriendObserver* observer)
mObservers.end());
}
+void LLAvatarTracker::idleNotifyObservers()
+{
+ if (mModifyMask == LLFriendObserver::NONE && mChangedBuddyIDs.size() == 0)
+ {
+ return;
+ }
+ notifyObservers();
+}
+
void LLAvatarTracker::notifyObservers()
{
+ if (mIsNotifyObservers)
+ {
+ // Don't allow multiple calls.
+ // new masks and ids will be processed later from idle.
+ return;
+ }
+ mIsNotifyObservers = TRUE;
+
observer_list_t observers(mObservers);
observer_list_t::iterator it = observers.begin();
observer_list_t::iterator end = observers.end();
@@ -490,6 +508,7 @@ void LLAvatarTracker::notifyObservers()
mModifyMask = LLFriendObserver::NONE;
mChangedBuddyIDs.clear();
+ mIsNotifyObservers = FALSE;
}
void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
@@ -531,7 +550,7 @@ void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)
// store flag for change
// and id of object change applies to
void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent)
-{
+{
mModifyMask |= mask;
if (referent.notNull())
{
diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h
index 6e5fc01cd8..1f819a42fd 100755
--- a/indra/newview/llcallingcard.h
+++ b/indra/newview/llcallingcard.h
@@ -143,6 +143,7 @@ public:
// observers left behind.
void addObserver(LLFriendObserver* observer);
void removeObserver(LLFriendObserver* observer);
+ void idleNotifyObservers();
void notifyObservers();
// Observers interested in updates of a particular avatar.
@@ -209,6 +210,8 @@ private:
LLAvatarTracker(const LLAvatarTracker&);
bool operator==(const LLAvatarTracker&);
+ BOOL mIsNotifyObservers;
+
public:
// don't you dare create or delete this object
LLAvatarTracker();
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index b0537a83f1..d6240838b6 100755
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -35,6 +35,7 @@
#include "llviewerwindow.h"
#include "llrootview.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterreg.h"
#include <algorithm>
@@ -131,7 +132,7 @@ void LLChannelManager::onLoginCompleted()
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index b81b95462e..dc0835eb1c 100755
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -376,6 +376,10 @@ public:
|| mSourceType == CHAT_SOURCE_SYSTEM)
{
mFrom = LLTrans::getString("SECOND_LIFE");
+ if(!chat.mFromName.empty() && (mFrom != chat.mFromName))
+ {
+ mFrom += " (" + chat.mFromName + ")";
+ }
user_name->setValue(mFrom);
updateMinUserNameWidth();
}
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 46b7679915..dedb06c945 100755
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -35,6 +35,7 @@
#include "llscriptfloater.h"
#include "llsingleton.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
@@ -165,7 +166,7 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)
mNotificationChannel.reset(new ChicletNotificationChannel(this));
// ensure that notification well window exists, to synchronously
// handle toast add/delete events.
- LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
+ LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);
}
void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
@@ -173,7 +174,7 @@ void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
std::string action = user_data.asString();
if("close all" == action)
{
- LLNotificationWellWindow::getInstance()->closeAll();
+ LLFloaterNotificationsTabbed::getInstance()->closeAll();
LLIMWellWindow::getInstance()->closeAll();
}
}
@@ -224,7 +225,8 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo
bool displayNotification;
if ( (notification->getName() == "ScriptDialog") // special case for scripts
// if there is no toast window for the notification, filter it
- || (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ //|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ || (!LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
)
{
displayNotification = false;
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index d8b04f7004..254e3f61a8 100755
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -31,6 +31,7 @@
#include "lllayoutstack.h"
#include "llpaneltopinfobar.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
namespace
{
@@ -49,7 +50,7 @@ BOOL LLChicletBar::postBuild()
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
- showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+ showWellButton("notification_well", !LLFloaterNotificationsTabbed::getInstance()->isWindowEmpty());
LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 19dba3f917..5ea7efc045 100755
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -30,6 +30,7 @@
#include "llcommandhandler.h"
#include "llnotificationsutil.h"
#include "llcommanddispatcherlistener.h"
+#include "llstartup.h"
#include "stringize.h"
// system includes
@@ -116,7 +117,11 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
if (! slurl_blocked)
{
- LLNotificationsUtil::add("BlockedSLURL");
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ // Note: commands can arrive before we initialize everything we need for Notification.
+ LLNotificationsUtil::add("BlockedSLURL");
+ }
slurl_blocked = true;
}
return true;
@@ -138,7 +143,10 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
if (! slurl_throttled)
{
- LLNotificationsUtil::add("ThrottledSLURL");
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ LLNotificationsUtil::add("ThrottledSLURL");
+ }
slurl_throttled = true;
}
return true;
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index 9545771c8d..219bcf0eb0 100755
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -57,7 +57,6 @@
#include "lltrans.h"
#include "llselectmgr.h"
-#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "llviewerassetupload.h"
@@ -358,8 +357,8 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(),
viewer_object->getID(), itemp);
- ExperienceAssociationResponder::fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
- boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1));
+ LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
+ boost::bind(&LLFloaterCompileQueue::requestAsset, datap, _1));
}
}
}
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index b38d472156..62f08144b9 100755
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -153,6 +153,7 @@ public:
* file name is conversation.log
*/
std::string getFileName();
+ LLConversation* findConversation(const LLIMModel::LLIMSession* session);
private:
@@ -184,7 +185,7 @@ private:
void updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name);
void updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages);
- LLConversation* findConversation(const LLIMModel::LLIMSession* session);
+
typedef std::vector<LLConversation> conversations_vec_t;
std::vector<LLConversation> mConversations;
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 6e32ce60ec..328a638f2f 100755
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -136,7 +136,24 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
items.push_back(std::string("im"));
items.push_back(std::string("offer_teleport"));
items.push_back(std::string("request_teleport"));
- items.push_back(std::string("voice_call"));
+
+ if (getType() != CONV_SESSION_1_ON_1)
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL;
+ if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel())
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ items.push_back(std::string("disconnect_from_voice"));
+ }
+ }
+
items.push_back(std::string("chat_history"));
items.push_back(std::string("separator_chat_history"));
items.push_back(std::string("add_friend"));
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 821d58a9b2..8bbc529244 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1553,7 +1553,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
(drawable && drawable->isState(LLDrawable::REBUILD_ALL)))
{
if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
- { //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
+ {
+ //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
for (S32 i = 0; i < drawable->getNumFaces(); ++i)
{
LLFace* facep = drawable->getFace(i);
@@ -1570,13 +1571,15 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
buffer = face->getVertexBuffer();
}
else
- { //just rebuild this face
+ {
+ //just rebuild this face
getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
}
}
if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime())
- { //perform software vertex skinning for this face
+ {
+ //perform software vertex skinning for this face
LLStrider<LLVector3> position;
LLStrider<LLVector3> normal;
@@ -1600,6 +1603,10 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
for (U32 j = 0; j < count; ++j)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (!joint)
+ {
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[j] = skin->mInvBindMatrix[j];
@@ -1624,12 +1631,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
{
F32 w = weight[j][k];
- idx[k] = llclamp((S32) floorf(w), 0, JOINT_COUNT-1);
+ idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)JOINT_COUNT-1);
wght[k] = w - floorf(w);
scale += wght[k];
}
-
+ // This is enforced in unpackVolumeFaces()
+ llassert(scale>0.f);
wght *= 1.f/scale;
for (U32 k = 0; k < 4; k++)
@@ -1729,6 +1737,10 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
for (U32 i = 0; i < count; ++i)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
+ if (!joint)
+ {
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[i] = skin->mInvBindMatrix[i];
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 33f7bc305c..7b9fd5c6c6 100755
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -864,6 +864,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
{
LLDrawInfo& params = **i;
+ gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);
LLDrawPoolBump::bindBumpMap(params, bump_channel);
pushBatch(params, mask, TRUE);
}
diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp
index 884d1579e6..8f2eb41307 100755
--- a/indra/newview/llestateinfomodel.cpp
+++ b/indra/newview/llestateinfomodel.cpp
@@ -153,7 +153,7 @@ void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url)
<< ", sun_hour = " << getSunHour() << LL_ENDL;
LL_DEBUGS() << body << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, body);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 0aad1d5ba9..40eaba2bac 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -120,14 +120,18 @@ namespace Details
void LLEventPollImpl::stop()
{
- LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL;
mDone = true;
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mAdapter.lock();
if (adapter)
{
+ LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL;
// cancel the yielding operation if any.
- adapter->cancelYieldingOperation();
+ adapter->cancelSuspendedOperation();
+ }
+ else
+ {
+ LL_INFOS() << "Coroutine for poll <" << mCounter << "> previously stopped. No action taken." << LL_ENDL;
}
}
@@ -154,7 +158,7 @@ namespace Details
// << LLSDXMLStreamer(request) << LL_ENDL;
LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(mHttpRequest, url, request);
+ LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request);
// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = "
// << LLSDXMLStreamer(result) << LL_ENDL;
@@ -179,6 +183,12 @@ namespace Details
LL_WARNS() << "Canceling coroutine" << LL_ENDL;
break;
}
+ else if (!status.isHttpStatus())
+ {
+ /// Some LLCore or LIBCurl error was returned. This is unlikely to be recoverable
+ LL_WARNS("LLEventPollImpl") << "Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL;
+ break;
+ }
LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
<< status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL;
@@ -197,7 +207,7 @@ namespace Details
" seconds, error count is now " << errorCount << LL_ENDL;
timeout.eventAfter(waitToRetry, LLSD());
- llcoro::waitForEventOn(timeout);
+ llcoro::suspendUntilEventOn(timeout);
if (mDone)
break;
diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h
index e32b4ed322..e2afd9226b 100755
--- a/indra/newview/lleventpoll.h
+++ b/indra/newview/lleventpoll.h
@@ -27,7 +27,6 @@
#ifndef LL_LLEVENTPOLL_H
#define LL_LLEVENTPOLL_H
-#include "llhttpclient.h"
#include "boost/move/unique_ptr.hpp"
namespace boost
diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp
deleted file mode 100644
index cd4a7516b1..0000000000
--- a/indra/newview/llexperienceassociationresponder.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file llexperienceassociationresponder.cpp
- * @brief llexperienceassociationresponder implementation. This class combines
- * a lookup for a script association and an experience details request. The first
- * is always async, but the second may be cached locally.
- *
- * $LicenseInfo:firstyear=2013&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2013, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llexperienceassociationresponder.h"
-#include "llexperiencecache.h"
-#include "llviewerregion.h"
-#include "llagent.h"
-
-ExperienceAssociationResponder::ExperienceAssociationResponder(ExperienceAssociationResponder::callback_t callback):mCallback(callback)
-{
- ref();
-}
-
-void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& object_id, const LLUUID& item_id, callback_t callback )
-{
- LLSD request;
- request["object-id"]=object_id;
- request["item-id"]=item_id;
- fetchAssociatedExperience(request, callback);
-}
-
-void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- std::string lookup_url=region->getCapability("GetMetadata");
- if(!lookup_url.empty())
- {
- LLSD fields;
- fields.append("experience");
- request["fields"] = fields;
- LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(callback));
- }
- }
-}
-
-void ExperienceAssociationResponder::httpFailure()
-{
- LLSD msg;
- msg["error"]=(LLSD::Integer)getStatus();
- msg["message"]=getReason();
- LL_INFOS("ExperienceAssociation") << "Failed to look up associated experience: " << getStatus() << ": " << getReason() << LL_ENDL;
-
- sendResult(msg);
-
-}
-void ExperienceAssociationResponder::httpSuccess()
-{
- if(!getContent().has("experience"))
- {
-
- LLSD msg;
- msg["message"]="no experience";
- msg["error"]=-1;
- sendResult(msg);
- return;
- }
-
- LLExperienceCache::getInstance()->get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
-
-}
-
-void ExperienceAssociationResponder::sendResult( const LLSD& experience )
-{
- mCallback(experience);
- unref();
-}
-
-
-
diff --git a/indra/newview/llexperienceassociationresponder.h b/indra/newview/llexperienceassociationresponder.h
deleted file mode 100644
index 2bdc3d251b..0000000000
--- a/indra/newview/llexperienceassociationresponder.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "llhttpclient.h"
-#include "llsd.h"
-/**
- * @file llexperienceassociationresponder.h
- * @brief llexperienceassociationresponder and related class definitions
- *
- * $LicenseInfo:firstyear=2013&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2013, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-
-
-#ifndef LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
-#define LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
-
-#include "llhttpclient.h"
-#include "llsd.h"
-
-class ExperienceAssociationResponder : public LLHTTPClient::Responder
-{
-public:
- typedef boost::function<void(const LLSD& experience)> callback_t;
-
- ExperienceAssociationResponder(callback_t callback);
-
- /*virtual*/ void httpSuccess();
- /*virtual*/ void httpFailure();
-
- static void fetchAssociatedExperience(const LLUUID& object_it, const LLUUID& item_id, callback_t callback);
-
-private:
- static void fetchAssociatedExperience(LLSD& request, callback_t callback);
-
- void sendResult(const LLSD& experience);
-
- callback_t mCallback;
-
-};
-
-#endif // LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index 136e02953c..1de4102dba 100755
--- a/indra/newview/llfacebookconnect.cpp
+++ b/indra/newview/llfacebookconnect.cpp
@@ -165,9 +165,7 @@ void LLFacebookConnect::facebookConnectCoro(std::string authCode, std::string au
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
-
- LLSD result = httpAdapter->putAndYield(httpRequest, getFacebookConnectURL("/connection"), putData, httpOpts, get_headers());
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getFacebookConnectURL("/connection"), putData, httpOpts, get_headers());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -242,9 +240,7 @@ void LLFacebookConnect::facebookShareCoro(std::string route, LLSD share)
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- setConnectionState(LLFacebookConnect::FB_POSTING);
-
- LLSD result = httpAdapter->postAndYield(httpRequest, getFacebookConnectURL(route, true), share, httpOpts, get_headers());
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), share, httpOpts, get_headers());
if (testShareStatus(result))
{
@@ -311,7 +307,7 @@ void LLFacebookConnect::facebookShareImageCoro(std::string route, LLPointer<LLIm
setConnectionState(LLFacebookConnect::FB_POSTING);
- LLSD result = httpAdapter->postAndYield(httpRequest, getFacebookConnectURL(route, true), raw, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), raw, httpOpts, httpHeaders);
if (testShareStatus(result))
{
@@ -331,10 +327,9 @@ void LLFacebookConnect::facebookDisconnectCoro()
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- setConnectionState(LLFacebookConnect::FB_DISCONNECTING);
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->deleteAndYield(httpRequest, getFacebookConnectURL("/connection"), httpOpts, get_headers());
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFacebookConnectURL("/connection"), httpOpts, get_headers());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -370,7 +365,7 @@ void LLFacebookConnect::facebookConnectedCheckCoro(bool autoConnect)
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/connection", true), httpOpts, get_headers());
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/connection", true), httpOpts, get_headers());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -418,7 +413,7 @@ void LLFacebookConnect::facebookConnectInfoCoro()
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/info", true), httpOpts, get_headers());
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/info", true), httpOpts, get_headers());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -461,7 +456,7 @@ void LLFacebookConnect::facebookConnectFriendsCoro()
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/friends", true), httpOpts, get_headers());
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/friends", true), httpOpts, get_headers());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -546,6 +541,8 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b
void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state)
{
+ setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
+
LLCoros::instance().launch("LLFacebookConnect::facebookConnectCoro",
boost::bind(&LLFacebookConnect::facebookConnectCoro, this, auth_code, auth_state));
}
@@ -558,6 +555,8 @@ void LLFacebookConnect::disconnectFromFacebook()
void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)
{
+ setConnectionState(LLFacebookConnect::FB_DISCONNECTING);
+
LLCoros::instance().launch("LLFacebookConnect::facebookConnectedCheckCoro",
boost::bind(&LLFacebookConnect::facebookConnectedCheckCoro, this, auto_connect));
}
@@ -583,6 +582,8 @@ void LLFacebookConnect::loadFacebookFriends()
void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name,
const std::string& description, const std::string& image, const std::string& message)
{
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLSD body;
if (!location.empty())
{
@@ -611,7 +612,8 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri
void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption)
{
- // *TODO: I could not find an instace where this method is used. Remove?
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLSD body;
body["image"] = image_url;
body["caption"] = caption;
@@ -622,6 +624,8 @@ void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::stri
void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption)
{
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLCoros::instance().launch("LLFacebookConnect::facebookShareImageCoro",
boost::bind(&LLFacebookConnect::facebookShareImageCoro, this, "/share/photo", image, caption));
}
@@ -631,6 +635,8 @@ void LLFacebookConnect::updateStatus(const std::string& message)
LLSD body;
body["message"] = message;
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro",
boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/wall", body));
}
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index f2b369a9ad..8f3eaaa207 100755
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -380,9 +380,11 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
- mTabsHighlightEnabled(TRUE)
- , mUpdateDropDownItems(true)
-, mRestoreOverflowMenu(false)
+ mTabsHighlightEnabled(TRUE),
+ mUpdateDropDownItems(true),
+ mRestoreOverflowMenu(false),
+ mGetPrevItems(true),
+ mItemsChangedTimer()
{
// Register callback for menus with current registrar (will be parent panel's registrar)
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
@@ -659,6 +661,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)
LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID());
}
updateButtons();
+ if (!mItemsChangedTimer.getStarted())
+ {
+ mItemsChangedTimer.start();
+ }
+ else
+ {
+ mItemsChangedTimer.reset();
+ }
+
}
}
@@ -693,6 +704,21 @@ void LLFavoritesBarCtrl::draw()
// Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)
mShowDragMarker = FALSE;
}
+ if (mItemsChangedTimer.getStarted())
+ {
+ if (mItemsChangedTimer.getElapsedTimeF32() > 1.f)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord();
+ mItemsChangedTimer.stop();
+ }
+ }
+
+ if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired)
+ {
+ LLFavoritesOrderStorage::instance().mUpdateRequired = false;
+ mItemsChangedTimer.start();
+ }
+
}
const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
@@ -723,6 +749,12 @@ void LLFavoritesBarCtrl::updateButtons()
return;
}
+ if(mGetPrevItems)
+ {
+ LLFavoritesOrderStorage::instance().mPrevFavorites = mItems;
+ mGetPrevItems = false;
+ }
+
const LLButton::Params& button_params = getButtonParams();
if(mItems.empty())
@@ -844,6 +876,7 @@ void LLFavoritesBarCtrl::updateButtons()
{
mUpdateDropDownItems = false;
}
+
}
LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset)
@@ -912,9 +945,11 @@ BOOL LLFavoritesBarCtrl::postBuild()
BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
{
+
if (mFavoriteFolderId.isNull())
return FALSE;
+
LLInventoryModel::cat_array_t cats;
LLIsType is_type(LLAssetType::AT_LANDMARK);
@@ -1411,6 +1446,7 @@ void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const
const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";
const S32 LLFavoritesOrderStorage::NO_INDEX = -1;
+bool LLFavoritesOrderStorage::mSaveOnExit = false;
void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index)
{
@@ -1447,6 +1483,7 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id)
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL;
onLandmarkLoaded(asset_id, lm);
}
+ return;
}
// static
@@ -1482,13 +1519,16 @@ void LLFavoritesOrderStorage::destroyClass()
LLFile::remove(old_filename);
}
- if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
- {
- LLFavoritesOrderStorage::instance().saveFavoritesSLURLs();
- }
- else
+ std::string filename = getSavedOrderFileName();
+ file.open(filename.c_str());
+ if (file.is_open())
{
- LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser();
+ file.close();
+ LLFile::remove(filename);
+ if(mSaveOnExit)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord(true);
+ }
}
}
@@ -1503,108 +1543,57 @@ std::string LLFavoritesOrderStorage::getSavedOrderFileName()
void LLFavoritesOrderStorage::load()
{
- // load per-resident sorting information
std::string filename = getSavedOrderFileName();
-
LLSD settings_llsd;
llifstream file;
file.open(filename.c_str());
if (file.is_open())
{
LLSDSerialize::fromXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
- << (settings_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL;
- }
-
- for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
- iter != settings_llsd.endMap(); ++iter)
- {
- mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
+ << (settings_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ file.close();
+ mSaveOnExit = true;
+
+ for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+ iter != settings_llsd.endMap(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ }
}
-}
-
-void LLFavoritesOrderStorage::saveFavoritesSLURLs()
-{
- // Do not change the file if we are not logged in yet.
- if (!LLLoginInstance::getInstance()->authSuccess())
+ else
{
- LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL;
- return;
+ filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ LLSD user_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
+ << (fav_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ in_file.close();
+ user_llsd = fav_llsd[gAgentUsername];
+
+ S32 index = 0;
+ for (LLSD::array_iterator iter = user_llsd.beginArray();
+ iter != user_llsd.endArray(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index));
+ index++;
+ }
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+ }
}
-
- std::string filename = getStoredFavoritesFilename();
- if (!filename.empty())
- {
- llifstream in_file;
- in_file.open(filename.c_str());
- LLSD fav_llsd;
- if (in_file.is_open())
- {
- LLSDSerialize::fromXML(fav_llsd, in_file);
- LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
- << (fav_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- in_file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
- }
-
- const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
-
- LLSD user_llsd;
- for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
- {
- LLSD value;
- value["name"] = (*it)->getName();
- value["asset_id"] = (*it)->getAssetUUID();
-
- slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
- if (slurl_iter != mSLURLs.end())
- {
- LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) << ", SLURL=" << slurl_iter->second << ", value=" << value << LL_ENDL;
- value["slurl"] = slurl_iter->second;
- user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL;
- }
- }
-
- LLAvatarName av_name;
- LLAvatarNameCache::get( gAgentID, &av_name );
- // Note : use the "John Doe" and not the "john.doe" version of the name
- // as we'll compare it with the stored credentials in the login panel.
- fav_llsd[av_name.getUserName()] = user_llsd;
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(fav_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName()
- << "' to '" << filename << "' "
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
- << "' at '" << filename << "' "
- << LL_ENDL;
- }
- }
}
void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
@@ -1626,8 +1615,30 @@ void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
// See saveFavoritesSLURLs() here above for the reason why.
if (fav_llsd.has(av_name.getUserName()))
{
- LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
- fav_llsd.erase(av_name.getUserName());
+ LLSD user_llsd = fav_llsd[av_name.getUserName()];
+
+ if (user_llsd.beginArray()->has("id"))
+ {
+ for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter)
+ {
+ LLSD value;
+ value["id"]= iter->get("id").asUUID();
+ iter->assign(value);
+ }
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ }
+ }
+ else
+ {
+ LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
+ fav_llsd.erase(av_name.getUserName());
+ }
}
llofstream out_file;
@@ -1648,20 +1659,20 @@ void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmar
if (landmark)
{
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL;
- LLVector3d pos_global;
- if (!landmark->getGlobalPos(pos_global))
- {
- // If global position was unknown on first getGlobalPos() call
- // it should be set for the subsequent calls.
- landmark->getGlobalPos(pos_global);
- }
+ LLVector3d pos_global;
+ if (!landmark->getGlobalPos(pos_global))
+ {
+ // If global position was unknown on first getGlobalPos() call
+ // it should be set for the subsequent calls.
+ landmark->getGlobalPos(pos_global);
+ }
- if (!pos_global.isExactlyZero())
- {
- LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
- LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
+ if (!pos_global.isExactlyZero())
+ {
+ LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
+ LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1));
- }
+ }
}
}
@@ -1671,41 +1682,6 @@ void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::st
mSLURLs[asset_id] = slurl;
}
-void LLFavoritesOrderStorage::save()
-{
- if (mIsDirty)
- {
- // something changed, so save it
- std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName();
- if (!filename.empty())
- {
- LLSD settings_llsd;
-
- for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter)
- {
- settings_llsd[iter->first.asString()] = iter->second;
- }
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL;
- }
- }
-}
-
-
void LLFavoritesOrderStorage::cleanup()
{
// nothing to clean
@@ -1720,7 +1696,7 @@ void LLFavoritesOrderStorage::cleanup()
sort_index_map_t aTempMap;
//copy unremoved values from mSortIndexes to aTempMap
- std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
+ std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
inserter(aTempMap, aTempMap.begin()),
is_not_in_fav);
@@ -1752,8 +1728,8 @@ void LLFavoritesOrderStorage::saveOrder()
void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items )
{
- int sortField = 0;
+ int sortField = 0;
// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
{
@@ -1793,6 +1769,110 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it
saveItemsOrder(items);
}
+BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)
+{
+
+ LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ if (favorite_folder.isNull())
+ return FALSE;
+
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::cat_array_t cats;
+
+ LLIsType is_type(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
+
+ std::sort(items.begin(), items.end(), LLFavoritesSort());
+
+ if((items != mPrevFavorites) || pref_changed)
+ {
+ std::string filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ in_file.close();
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+
+ LLSD user_llsd;
+ S32 fav_iter = 0;
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
+ {
+ LLSD value;
+ if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
+ {
+ value["name"] = (*it)->getName();
+ value["asset_id"] = (*it)->getAssetUUID();
+ value["id"] = (*it)->getUUID();
+ slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
+ if (slurl_iter != mSLURLs.end())
+ {
+ value["slurl"] = slurl_iter->second;
+ user_llsd[fav_iter] = value;
+ }
+ else
+ {
+ getSLURL((*it)->getAssetUUID());
+ mUpdateRequired = true;
+ return FALSE;
+ }
+ }
+ else
+ {
+ value["id"] = (*it)->getUUID();
+ user_llsd[fav_iter] = value;
+ }
+
+ fav_iter ++;
+ }
+
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ // Note : use the "John Doe" and not the "john.doe" version of the name
+ // as we'll compare it with the stored credentials in the login panel.
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ mSaveOnExit = false;
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
+ << "' at '" << filename << "' " << LL_ENDL;
+ }
+ }
+
+ mPrevFavorites = items;
+ }
+
+ return TRUE;
+
+}
+
+void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show)
+{
+ if (show)
+ {
+ saveFavoritesRecord(true);
+ }
+ else
+ {
+ removeFavoritesRecordOfUser();
+ }
+}
+
void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
{
if (mTargetLandmarkId.isNull()) return;
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index a370724947..66fc8b2ae7 100755
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -105,8 +105,10 @@ protected:
bool mUpdateDropDownItems;
bool mRestoreOverflowMenu;
- LLUUID mSelectedItemID;
+ bool mGetPrevItems;
+ LLUUID mSelectedItemID;
+ LLFrameTimer mItemsChangedTimer;
LLUIImage* mImageDragIndication;
private:
@@ -204,12 +206,23 @@ public:
* @see cleanup()
*/
static void destroyClass();
+ static std::string getStoredFavoritesFilename();
+ static std::string getSavedOrderFileName();
+
+ BOOL saveFavoritesRecord(bool pref_changed = false);
+ void showFavoritesOnLoginChanged(BOOL show);
+
+ LLInventoryModel::item_array_t mPrevFavorites;
+
const static S32 NO_INDEX;
+ static bool mSaveOnExit;
+ bool mUpdateRequired;
+
private:
friend class LLSingleton<LLFavoritesOrderStorage>;
- LLFavoritesOrderStorage() : mIsDirty(false) { load(); }
- ~LLFavoritesOrderStorage() { save(); }
+ LLFavoritesOrderStorage() : mIsDirty(false), mUpdateRequired(false){ load(); }
+ ~LLFavoritesOrderStorage() {}
/**
* Removes sort indexes for items which are not in Favorites bar for now.
@@ -217,13 +230,8 @@ private:
void cleanup();
const static std::string SORTING_DATA_FILE_NAME;
- std::string getSavedOrderFileName();
- static std::string getStoredFavoritesFilename();
-
- void load();
- void save();
- void saveFavoritesSLURLs();
+ void load();
// Remove record of current user's favorites from file on disk.
void removeFavoritesRecordOfUser();
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 0b76ca16a9..f08064d9b5 100755
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -526,7 +526,7 @@ void LLFeatureManager::fetchFeatureTableCoro(std::string tableName)
LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL;
- LLSD result = httpAdapter->getRawAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -536,13 +536,13 @@ void LLFeatureManager::fetchFeatureTableCoro(std::string tableName)
// write to file
const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
- LL_INFOS() << "writing feature table to " << filename << LL_ENDL;
+ LL_INFOS() << "writing feature table to " << path << LL_ENDL;
S32 size = raw.size();
if (size > 0)
{
// write to file
- LLAPRFile out(filename, LL_APR_WB);
+ LLAPRFile out(path, LL_APR_WB);
out.write(raw.data(), size);
out.close();
}
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index ef50594feb..a7236d1778 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -40,6 +40,10 @@
#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
#endif // LL_SDL
+#if LL_LINUX || LL_SOLARIS
+#include "llhttpconstants.h" // file picker uses some of thes constants on Linux
+#endif
+
//
// Globals
//
diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp
index 83e4f19191..c0ca5b8cf8 100644
--- a/indra/newview/llflickrconnect.cpp
+++ b/indra/newview/llflickrconnect.cpp
@@ -86,7 +86,7 @@ void LLFlickrConnect::flickrConnectCoro(std::string requestToken, std::string oa
setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
- LLSD result = httpAdapter->putAndYield(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts);
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -168,9 +168,7 @@ void LLFlickrConnect::flickrShareCoro(LLSD share)
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- setConnectionState(LLFlickrConnect::FLICKR_POSTING);
-
- LLSD result = httpAdapter->postAndYield(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts);
if (testShareStatus(result))
{
@@ -248,7 +246,7 @@ void LLFlickrConnect::flickrShareImageCoro(LLPointer<LLImageFormatted> image, st
body << "\r\n--" << boundary << "--\r\n";
- LLSD result = httpAdapter->postAndYield(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
if (testShareStatus(result))
{
@@ -271,7 +269,7 @@ void LLFlickrConnect::flickrDisconnectCoro()
setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING);
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->deleteAndYield(httpRequest, getFlickrConnectURL("/connection"), httpOpts);
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFlickrConnectURL("/connection"), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -306,7 +304,7 @@ void LLFlickrConnect::flickrConnectedCoro(bool autoConnect)
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getFlickrConnectURL("/connection", true), httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/connection", true), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -355,7 +353,7 @@ void LLFlickrConnect::flickrInfoCoro()
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getFlickrConnectURL("/info", true), httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/info", true), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -471,12 +469,15 @@ void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::strin
body["tags"] = tags;
body["safety_level"] = safety_level;
+ setConnectionState(LLFlickrConnect::FLICKR_POSTING);
+
LLCoros::instance().launch("LLFlickrConnect::flickrShareCoro",
boost::bind(&LLFlickrConnect::flickrShareCoro, this, body));
}
void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
{
+ setConnectionState(LLFlickrConnect::FLICKR_POSTING);
LLCoros::instance().launch("LLFlickrConnect::flickrShareImageCoro",
boost::bind(&LLFlickrConnect::flickrShareImageCoro, this, image,
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 01c9416973..bababca652 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -34,10 +34,12 @@
// Viewer includes
#include "llagent.h"
#include "llagentui.h"
-#include "llappviewer.h"
+#include "llappviewer.h"
+#include "llnotificationsutil.h"
#include "llslurl.h"
#include "llvoiceclient.h"
#include "lluictrlfactory.h"
+#include "llupdaterservice.h"
#include "llviewertexteditor.h"
#include "llviewercontrol.h"
#include "llviewerstats.h"
@@ -48,7 +50,6 @@
// Linden library includes
#include "llaudioengine.h"
#include "llbutton.h"
-#include "llcurl.h"
#include "llglheaders.h"
#include "llfloater.h"
#include "llfloaterreg.h"
@@ -88,10 +89,24 @@ public:
/// separated so that we can programmatically access the same info.
static LLSD getInfo();
void onClickCopyToClipboard();
+ void onClickUpdateCheck();
+
+ // checks state of updater service and starts a check outside of schedule.
+ // subscribes callback for closest state update
+ static void setUpdateListener();
private:
void setSupportText(const std::string& server_release_notes_url);
+ // notifications for user requested checks
+ static void showCheckUpdateNotification(S32 state);
+
+ // callback method for manual checks
+ static bool callbackCheckUpdate(LLSD const & event);
+
+ // listener name for update checks
+ static const std::string sCheckUpdateListenerName;
+
static void startFetchServerReleaseNotes();
static void handleServerReleaseNotes(LLSD results);
};
@@ -124,6 +139,9 @@ BOOL LLFloaterAbout::postBuild()
getChild<LLUICtrl>("copy_btn")->setCommitCallback(
boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
+ getChild<LLUICtrl>("update_btn")->setCommitCallback(
+ boost::bind(&LLFloaterAbout::onClickUpdateCheck, this));
+
static const LLUIColor about_color = LLUIColorTable::instance().getColor("TextFgReadOnlyColor");
if (gAgent.getRegion())
@@ -271,6 +289,11 @@ void LLFloaterAbout::onClickCopyToClipboard()
support_widget->deselect();
}
+void LLFloaterAbout::onClickUpdateCheck()
+{
+ setUpdateListener();
+}
+
void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
{
#if LL_WINDOWS
@@ -292,6 +315,68 @@ void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
}
///----------------------------------------------------------------------------
+/// Floater About Update-check related functions
+///----------------------------------------------------------------------------
+
+const std::string LLFloaterAbout::sCheckUpdateListenerName = "LLUpdateNotificationListener";
+
+void LLFloaterAbout::showCheckUpdateNotification(S32 state)
+{
+ switch (state)
+ {
+ case LLUpdaterService::UP_TO_DATE:
+ LLNotificationsUtil::add("UpdateViewerUpToDate");
+ break;
+ case LLUpdaterService::DOWNLOADING:
+ case LLUpdaterService::INSTALLING:
+ LLNotificationsUtil::add("UpdateDownloadInProgress");
+ break;
+ case LLUpdaterService::TERMINAL:
+ // download complete, user triggered check after download pop-up appeared
+ LLNotificationsUtil::add("UpdateDownloadComplete");
+ break;
+ default:
+ LLNotificationsUtil::add("UpdateCheckError");
+ break;
+ }
+}
+
+bool LLFloaterAbout::callbackCheckUpdate(LLSD const & event)
+{
+ if (!event.has("payload"))
+ {
+ return false;
+ }
+
+ LLSD payload = event["payload"];
+ if (payload.has("type") && payload["type"].asInteger() == LLUpdaterService::STATE_CHANGE)
+ {
+ LLEventPumps::instance().obtain("mainlooprepeater").stopListening(sCheckUpdateListenerName);
+ showCheckUpdateNotification(payload["state"].asInteger());
+ }
+ return false;
+}
+
+void LLFloaterAbout::setUpdateListener()
+{
+ LLUpdaterService update_service;
+ S32 service_state = update_service.getState();
+ // Note: Do not set state listener before forceCheck() since it set's new state
+ if (update_service.forceCheck() || service_state == LLUpdaterService::CHECKING_FOR_UPDATE)
+ {
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainlooprepeater"));
+ if (mainloop.getListener(sCheckUpdateListenerName) == LLBoundListener()) // dummy listener
+ {
+ mainloop.listen(sCheckUpdateListenerName, boost::bind(&callbackCheckUpdate, _1));
+ }
+ }
+ else
+ {
+ showCheckUpdateNotification(service_state);
+ }
+}
+
+///----------------------------------------------------------------------------
/// LLFloaterAboutUtil
///----------------------------------------------------------------------------
void LLFloaterAboutUtil::registerFloater()
@@ -301,3 +386,8 @@ void LLFloaterAboutUtil::registerFloater()
}
+void LLFloaterAboutUtil::checkUpdatesAndNotify()
+{
+ LLFloaterAbout::setUpdateListener();
+}
+
diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h
index 8fc1aa4f29..be34b631cc 100755
--- a/indra/newview/llfloaterabout.h
+++ b/indra/newview/llfloaterabout.h
@@ -30,6 +30,9 @@
namespace LLFloaterAboutUtil
{
void registerFloater();
+
+ // Support for user initialized update/state checks
+ void checkUpdatesAndNotify();
}
#endif // LL_LLFLOATERABOUT_H
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 2824038f77..72892b47a4 100755
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -466,7 +466,7 @@ void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::strin
LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index 34904cf7ed..957c91b226 100755
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -32,6 +32,7 @@
#include "llavataractions.h"
#include "llfloaterbump.h"
+#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llmutelist.h"
#include "llpanelblockedlist.h"
@@ -87,11 +88,11 @@ BOOL LLFloaterBump::postBuild()
// virtual
void LLFloaterBump::onOpen(const LLSD& key)
{
- mNames.clear();
- mList->deleteAllItems();
-
if (gMeanCollisionList.empty())
{
+ mNames.clear();
+ mList->deleteAllItems();
+
std::string none_detected = getString("none_detected");
LLSD row;
row["columns"][0]["value"] = none_detected;
@@ -100,12 +101,20 @@ void LLFloaterBump::onOpen(const LLSD& key)
}
else
{
- for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
- iter != gMeanCollisionList.end(); ++iter)
- {
- LLMeanCollisionData *mcd = *iter;
- add(mList, mcd);
- }
+ populateCollisionList();
+ }
+}
+
+void LLFloaterBump::populateCollisionList()
+{
+ mNames.clear();
+ mList->deleteAllItems();
+
+ for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ iter != gMeanCollisionList.end(); ++iter)
+ {
+ LLMeanCollisionData *mcd = *iter;
+ add(mList, mcd);
}
}
@@ -247,3 +256,8 @@ void LLFloaterBump::inviteToGroup()
{
LLAvatarActions::inviteToGroup(mItemUUID);
}
+
+LLFloaterBump* LLFloaterBump::getInstance()
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterBump>("bumps");
+}
diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h
index 11b7db9fee..ce52c75255 100755
--- a/indra/newview/llfloaterbump.h
+++ b/indra/newview/llfloaterbump.h
@@ -46,6 +46,10 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ static LLFloaterBump* getInstance();
+
+ void populateCollisionList();
+
void startIM();
void startCall();
void reportAbuse();
diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp
index 8a04f9e4cc..d44eb4310d 100644
--- a/indra/newview/llfloaterexperienceprofile.cpp
+++ b/indra/newview/llfloaterexperienceprofile.cpp
@@ -36,7 +36,6 @@
#include "llexpandabletextbox.h"
#include "llexperiencecache.h"
#include "llfloaterreg.h"
-#include "llhttpclient.h"
#include "lllayoutstack.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
@@ -99,7 +98,7 @@ public:
if(params.size() != 2 || params[1].asString() != "profile")
return false;
- LLExperienceCache::getInstance()->get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
+ LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
return true;
}
@@ -131,175 +130,20 @@ LLFloaterExperienceProfile::~LLFloaterExperienceProfile()
}
-template<class T>
-class HandleResponder : public LLHTTPClient::Responder
-{
-public:
- HandleResponder(const LLHandle<T>& parent):mParent(parent){}
- LLHandle<T> mParent;
-
- virtual void httpFailure()
- {
- LL_WARNS() << "HandleResponder failed with code: " << getStatus() << ", reason: " << getReason() << LL_ENDL;
- }
-};
-
-class ExperienceUpdateResponder : public HandleResponder<LLFloaterExperienceProfile>
-{
-public:
- ExperienceUpdateResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent)
- {
- }
-
- virtual void httpSuccess()
- {
- LLFloaterExperienceProfile* parent=mParent.get();
- if(parent)
- {
- parent->onSaveComplete(getContent());
- }
- }
-};
-
-
-
-class ExperiencePreferencesResponder : public LLHTTPClient::Responder
-{
-public:
- ExperiencePreferencesResponder(const LLUUID& single = LLUUID::null):mId(single)
- {
- }
-
- bool sendSingle(const LLSD& content, const LLSD& permission, const char* name)
- {
- if(!content.has(name))
- return false;
-
- LLEventPump& pump = LLEventPumps::instance().obtain("experience_permission");
- const LLSD& list = content[name];
- LLSD::array_const_iterator it = list.beginArray();
- while(it != list.endArray())
- {
- if(it->asUUID() == mId)
- {
- LLSD message;
- message[it->asString()] = permission;
- message["experience"] = mId;
- pump.post(message);
- return true;
- }
- ++it;
- }
- return false;
- }
-
- bool hasPermission(const LLSD& content, const char* name)
- {
- if(!content.has(name))
- return false;
-
- const LLSD& list = content[name];
- LLSD::array_const_iterator it = list.beginArray();
- while(it != list.endArray())
- {
- if(it->asUUID() == mId)
- {
- return true;
- }
- ++it;
- }
- return false;
- }
-
- const char* getPermission(const LLSD& content)
- {
- if(hasPermission(content, "experiences"))
- {
- return "Allow";
- }
- else if(hasPermission(content, "blocked"))
- {
- return "Block";
- }
- return "Forget";
- }
-
-
- virtual void httpSuccess()
- {
- if(mId.notNull())
- {
- post(getPermission(getContent()));
- return;
- }
- LLEventPumps::instance().obtain("experience_permission").post(getContent());
- }
-
- void post( const char* perm )
- {
- LLSD experience;
- LLSD message;
- experience["permission"]=perm;
- message["experience"] = mId;
- message[mId.asString()] = experience;
- LLEventPumps::instance().obtain("experience_permission").post(message);
- }
-
-private:
- LLUUID mId;
-};
-
-
-class IsAdminResponder : public HandleResponder<LLFloaterExperienceProfile>
-{
-public:
- IsAdminResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent)
- {
- }
-
- virtual void httpSuccess()
- {
- LLFloaterExperienceProfile* parent = mParent.get();
- if(!parent)
- return;
-
- bool enabled = true;
- LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- enabled = false;
- }
- else
- {
- std::string url=region->getCapability("UpdateExperience");
- if(url.empty())
- enabled = false;
- }
- if(enabled && getContent()["status"].asBoolean())
- {
- parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE);
- parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE);
- }
- }
-};
-
BOOL LLFloaterExperienceProfile::postBuild()
{
if (mExperienceId.notNull())
{
- LLExperienceCache::getInstance()->fetch(mExperienceId, true);
- LLExperienceCache::getInstance()->get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
+ LLExperienceCache::instance().fetch(mExperienceId, true);
+ LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
getDerivedHandle<LLFloaterExperienceProfile>(), _1));
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- std::string lookup_url=region->getCapability("IsExperienceAdmin");
- if(!lookup_url.empty())
- {
- LLHTTPClient::get(lookup_url+"?experience_id="+mExperienceId.asString(), new IsAdminResponder(getDerivedHandle<LLFloaterExperienceProfile>()));
- }
+ LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
}
@@ -372,23 +216,13 @@ void LLFloaterExperienceProfile::onClickSave()
doSave(NOTHING);
}
-
void LLFloaterExperienceProfile::onClickPermission(const char* perm)
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
-
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return;
- LLSD permission;
- LLSD data;
- permission["permission"]=perm;
-
- data[mExperienceId.asString()]=permission;
- LLHTTPClient::put(lookup_url, data, new ExperiencePreferencesResponder(mExperienceId));
-
+ LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
@@ -398,11 +232,8 @@ void LLFloaterExperienceProfile::onClickForget()
if (!region)
return;
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return;
-
- LLHTTPClient::del(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId));
+ LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo )
@@ -549,11 +380,8 @@ void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience )
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(!lookup_url.empty())
- {
- LLHTTPClient::get(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId));
- }
+ LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
}
@@ -733,15 +561,9 @@ void LLFloaterExperienceProfile::doSave( int success_action )
if (!region)
return;
- std::string url=region->getCapability("UpdateExperience");
- if(url.empty())
- return;
-
- mPackage.erase(LLExperienceCache::QUOTA);
- mPackage.erase(LLExperienceCache::EXPIRES);
- mPackage.erase(LLExperienceCache::AGENT_ID);
-
- LLHTTPClient::post(url, mPackage, new ExperienceUpdateResponder(getDerivedHandle<LLFloaterExperienceProfile>()));
+ LLExperienceCache::instance().updateExperience(mPackage, boost::bind(
+ &LLFloaterExperienceProfile::experienceUpdateResult,
+ getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
@@ -799,8 +621,8 @@ void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
}
refreshExperience(*it);
- LLExperienceCache::getInstance()->insert(*it);
- LLExperienceCache::getInstance()->fetch(id, true);
+ LLExperienceCache::instance().insert(*it);
+ LLExperienceCache::instance().fetch(id, true);
if(mSaveCompleteAction==VIEW)
{
@@ -1002,3 +824,76 @@ void LLFloaterExperienceProfile::onReportExperience()
{
LLFloaterReporter::showFromExperience(mExperienceId);
}
+
+/*static*/
+bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test)
+{
+ if (!content.has(name))
+ return false;
+
+ const LLSD& list = content[name];
+ LLSD::array_const_iterator it = list.beginArray();
+ while (it != list.endArray())
+ {
+ if (it->asUUID() == test)
+ {
+ return true;
+ }
+ ++it;
+ }
+ return false;
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experiencePermissionResults(LLUUID exprienceId, LLSD result)
+{
+ std::string permission("Forget");
+ if (hasPermission(result, "experiences", exprienceId))
+ permission = "Allow";
+ else if (hasPermission(result, "blocked", exprienceId))
+ permission = "Block";
+
+ LLSD experience;
+ LLSD message;
+ experience["permission"] = permission;
+ message["experience"] = exprienceId;
+ message[exprienceId.asString()] = experience;
+
+ LLEventPumps::instance().obtain("experience_permission").post(message);
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
+{
+ LLFloaterExperienceProfile* parent = handle.get();
+ if (!parent)
+ return;
+
+ bool enabled = true;
+ LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ enabled = false;
+ }
+ else
+ {
+ std::string url = region->getCapability("UpdateExperience");
+ if (url.empty())
+ enabled = false;
+ }
+ if (enabled && result["status"].asBoolean())
+ {
+ parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE);
+ parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE);
+ }
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
+{
+ LLFloaterExperienceProfile* parent = handle.get();
+ if (parent)
+ {
+ parent->onSaveComplete(result);
+ }
+}
diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h
index 78d54eb447..7a5ced546b 100644
--- a/indra/newview/llfloaterexperienceprofile.h
+++ b/indra/newview/llfloaterexperienceprofile.h
@@ -99,6 +99,12 @@ protected:
int mSaveCompleteAction;
bool mDirty;
bool mForceClose;
+
+private:
+ static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test);
+ static void experiencePermissionResults(LLUUID exprienceId, LLSD result);
+ static void experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
+ static void experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
};
#endif // LL_LLFLOATEREXPERIENCEPROFILE_H
diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp
index 14fbdb3a8f..fbe00beddd 100644
--- a/indra/newview/llfloaterexperiences.cpp
+++ b/indra/newview/llfloaterexperiences.cpp
@@ -32,7 +32,6 @@
#include "llevents.h"
#include "llexperiencecache.h"
#include "llfloaterregioninfo.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
#include "llpanelexperiencepicker.h"
@@ -294,7 +293,7 @@ void LLFloaterExperiences::retrieveExperienceList(const std::string &url,
// _3 -> url
// _4 -> httpOptions
// _5 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndYield), _1, _2, _3, _4, _5);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _4, _5);
LLCoros::instance().launch("LLFloaterExperiences::retrieveExperienceList",
boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
@@ -315,7 +314,7 @@ void LLFloaterExperiences::requestNewExperience(const std::string &url,
// _3 -> url
// _4 -> httpOptions
// _5 -> httpHeaders
- (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndYield), _1, _2, _3, LLSD(), _4, _5);
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, LLSD(), _4, _5);
LLCoros::instance().launch("LLFloaterExperiences::requestNewExperience",
boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp
index 3a2047cfef..da85d378b2 100644
--- a/indra/newview/llfloaterfacebook.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -64,9 +64,9 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo
const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";
const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare";
-const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
-const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
-const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook
+const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
+const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
+const S32 TARGET_DATA_SIZE = 950000; // Size of the image (compressed) we're trying to send to Facebook
std::string get_map_url()
{
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index ab57e8c170..f1a6ef78a6 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -261,6 +261,8 @@ BOOL LLFloaterIMContainer::postBuild()
mInitialized = true;
+ mIsFirstOpen = true;
+
// Add callbacks:
// We'll take care of view updates on idle
gIdleCallbacks.addFunction(idle, this);
@@ -636,14 +638,16 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
{
// Make sure we have the Nearby Chat present when showing the conversation container
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
- if (nearby_chat == NULL)
+ if ((nearby_chat == NULL) || mIsFirstOpen)
{
+ mIsFirstOpen = false;
// If not found, force the creation of the nearby chat conversation panel
// *TODO: find a way to move this to XML as a default panel or something like that
LLSD name("nearby_chat");
LLFloaterReg::toggleInstanceOrBringToFront(name);
selectConversationPair(LLUUID(NULL), false, false);
}
+
flashConversationItemWidget(mSelectedSession,false);
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);
@@ -1216,7 +1220,22 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
{
if (selectedIDS.size() > 0)
{
- LLAvatarActions::viewChatHistory(selectedIDS.front());
+ if(conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conversationItem->getUUID(), true);
+ }
+ else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(conversationItem->getUUID()));
+ if(conv)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conv->getSessionID(), true);
+ }
+ }
+ else
+ {
+ LLAvatarActions::viewChatHistory(selectedIDS.front());
+ }
}
}
else
@@ -1316,6 +1335,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
{
return LLLogChat::isNearbyTranscriptExist();
}
+ else if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ const LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(uuids.front()));
+ if(conv)
+ {
+ return LLLogChat::isAdHocTranscriptExist(conv->getHistoryFileName());
+ }
+ return false;
+ }
else
{
bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP);
@@ -1881,22 +1909,28 @@ bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid)
return false;
}
- if (!gdatap->mMembers.size())
+ if (gdatap->mPendingBanRequest)
{
return false;
}
- LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
- if (mi == gdatap->mMembers.end())
+ if (gdatap->isRoleMemberDataComplete())
{
- return false;
- }
+ if (!gdatap->mMembers.size())
+ {
+ return false;
+ }
- LLGroupMemberData* member_data = (*mi).second;
- // Is the member an owner?
- if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
- {
- return false;
+ LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
+ if (mi != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member_data = (*mi).second;
+ // Is the member an owner?
+ if (member_data && member_data->isInRole(gdatap->mOwnerRole))
+ {
+ return false;
+ }
+ }
}
if( gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) &&
@@ -1924,20 +1958,8 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)
LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;
return;
}
- std::vector<LLUUID> ids;
- ids.push_back(participant_uuid);
-
- LLGroupBanData ban_data;
- gdatap->createBanEntry(participant_uuid, ban_data);
- LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids);
- LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids);
- LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid);
- LLSD args;
- std::string name;
- gCacheName->getFullName(participant_uuid, name);
- args["AVATAR_NAME"] = name;
- args["GROUP_NAME"] = gdatap->mName;
- LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+
+ gdatap->banMemberById(participant_uuid);
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index f21c0b9947..60cef83d9a 100755
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -193,6 +193,8 @@ private:
bool mInitialized;
bool mIsFirstLaunch;
+ bool mIsFirstOpen;
+
LLUUID mSelectedSession;
std::string mGeneralTitle;
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index b7fff6cae3..ee3d633dd0 100755
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -326,7 +326,21 @@ void LLFloaterJoystick::onClickOK(void *joy_panel)
}
}
+void LLFloaterJoystick::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+ closeFloater(app_quitting);
+}
+
void LLFloaterJoystick::setSNDefaults()
{
LLViewerJoystick::getInstance()->setSNDefaults();
}
+
+void LLFloaterJoystick::onClose(bool app_quitting)
+{
+ if (app_quitting)
+ {
+ cancel();
+ }
+}
diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h
index 9c3752540d..a1b5951389 100755
--- a/indra/newview/llfloaterjoystick.h
+++ b/indra/newview/llfloaterjoystick.h
@@ -45,6 +45,11 @@ public:
virtual void draw();
static void setSNDefaults();
+protected:
+
+ void onClose(bool app_quitting);
+ void onClickCloseBtn(bool app_quitting);
+
private:
LLFloaterJoystick(const LLSD& data);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index ce32aeda94..f9fd5069af 100755
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -2439,6 +2439,8 @@ void LLPanelLandAccess::refresh()
mListAccess->clearSortOrder();
mListAccess->deleteAllItems();
S32 count = parcel->mAccessList.size();
+ getChild<LLUICtrl>("AllowedText")->setTextArg("[COUNT]", llformat("%d",count));
+
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
@@ -2484,6 +2486,7 @@ void LLPanelLandAccess::refresh()
mListBanned->clearSortOrder();
mListBanned->deleteAllItems();
S32 count = parcel->mBanList.size();
+ getChild<LLUICtrl>("BanCheck")->setTextArg("[COUNT]", llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index b2d36479cd..18f0bc4498 100755
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -572,7 +572,7 @@ void LLFloaterMarketplaceListings::updateView()
std::string title;
std::string tooltip;
- const LLSD& subs = getMarketplaceStringSubstitutions();
+ const LLSD& subs = LLMarketplaceData::getMarketplaceStringSubstitutions();
// Update the top message or flip to the tabs and folders view
// *TODO : check those messages and create better appropriate ones in strings.xml
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 47130dbb43..05b4ecafe6 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -26,35 +26,8 @@
#include "llviewerprecompiledheaders.h"
-#if LL_MSVC
-#pragma warning (disable : 4263)
-#pragma warning (disable : 4264)
-#endif
-#include "dae.h"
-//#include "dom.h"
-#include "dom/domAsset.h"
-#include "dom/domBind_material.h"
-#include "dom/domCOLLADA.h"
-#include "dom/domConstants.h"
-#include "dom/domController.h"
-#include "dom/domEffect.h"
-#include "dom/domGeometry.h"
-#include "dom/domInstance_geometry.h"
-#include "dom/domInstance_material.h"
-#include "dom/domInstance_node.h"
-#include "dom/domInstance_effect.h"
-#include "dom/domMaterial.h"
-#include "dom/domMatrix.h"
-#include "dom/domNode.h"
-#include "dom/domProfile_COMMON.h"
-#include "dom/domRotate.h"
-#include "dom/domScale.h"
-#include "dom/domTranslate.h"
-#include "dom/domVisual_scene.h"
-#if LL_MSVC
-#pragma warning (default : 4263)
-#pragma warning (default : 4264)
-#endif
+#include "llmodelloader.h"
+#include "lldaeloader.h"
#include "llfloatermodelpreview.h"
@@ -112,14 +85,15 @@
#include "llanimationstates.h"
#include "llviewernetwork.h"
#include "llviewershadermgr.h"
-#include "glod/glod.h"
-const S32 SLM_SUPPORTED_VERSION = 3;
+#include "glod/glod.h"
+#include <boost/algorithm/string.hpp>
//static
S32 LLFloaterModelPreview::sUploadAmount = 10;
LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
-std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
+
+bool LLModelPreview::sIgnoreLoadedCallback = false;
// "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01
// But according to the UI spec for upload model floater, this parameter
@@ -199,190 +173,46 @@ std::string lod_label_name[NUM_LOD+1] =
"I went off the end of the lod_label_name array. Me so smart."
};
-std::string colladaVersion[VERSIONTYPE_COUNT+1] =
-{
- "1.4.0",
- "1.4.1",
- "Unsupported"
-};
-
-
-#define LL_DEGENERACY_TOLERANCE 1e-7f
-
-inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
-{
- volatile F32 p0 = a[0] * b[0];
- volatile F32 p1 = a[1] * b[1];
- volatile F32 p2 = a[2] * b[2];
- return p0 + p1 + p2;
-}
-
-bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
-{
- // small area check
- {
- LLVector4a edge1; edge1.setSub( a, b );
- LLVector4a edge2; edge2.setSub( a, c );
- //////////////////////////////////////////////////////////////////////////
- /// Linden Modified
- //////////////////////////////////////////////////////////////////////////
-
- // If no one edge is more than 10x longer than any other edge, we weaken
- // the tolerance by a factor of 1e-4f.
-
- LLVector4a edge3; edge3.setSub( c, b );
- const F32 len1sq = edge1.dot3(edge1).getF32();
- const F32 len2sq = edge2.dot3(edge2).getF32();
- const F32 len3sq = edge3.dot3(edge3).getF32();
- bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
- bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
- bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
- if ( abOK && acOK && cbOK )
- {
- tolerance *= 1e-4f;
- }
-
- //////////////////////////////////////////////////////////////////////////
- /// End Modified
- //////////////////////////////////////////////////////////////////////////
-
- LLVector4a cross; cross.setCross3( edge1, edge2 );
-
- LLVector4a edge1b; edge1b.setSub( b, a );
- LLVector4a edge2b; edge2b.setSub( b, c );
- LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
-
- if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
- {
- return true;
- }
- }
-
- // point triangle distance check
- {
- LLVector4a Q; Q.setSub(a, b);
- LLVector4a R; R.setSub(c, b);
-
- const F32 QQ = dot3fpu(Q, Q);
- const F32 RR = dot3fpu(R, R);
- const F32 QR = dot3fpu(R, Q);
-
- volatile F32 QQRR = QQ * RR;
- volatile F32 QRQR = QR * QR;
- F32 Det = (QQRR - QRQR);
-
- if( Det == 0.0f )
- {
- return true;
- }
- }
-
- return false;
-}
-
-bool validate_face(const LLVolumeFace& face)
+BOOL stop_gloderror()
{
+ GLuint error = glodGetError();
- for (U32 v = 0; v < face.mNumVertices; v++)
- {
- if(face.mPositions && !face.mPositions[v].isFinite3())
- {
- LL_WARNS() << "NaN position data in face found!" << LL_ENDL;
- return false;
- }
-
- if(face.mNormals && !face.mNormals[v].isFinite3())
- {
- LL_WARNS() << "NaN normal data in face found!" << LL_ENDL;
- return false;
- }
- }
-
- for (U32 i = 0; i < face.mNumIndices; ++i)
- {
- if (face.mIndices[i] >= face.mNumVertices)
- {
- LL_WARNS() << "Face has invalid index." << LL_ENDL;
- return false;
- }
- }
-
- if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+ if (error != GLOD_NO_ERROR)
{
- LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
- return false;
+ LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
+ return TRUE;
}
-
- /*const LLVector4a scale(0.5f);
-
-
- for (U32 i = 0; i < face.mNumIndices; i+=3)
- {
- U16 idx1 = face.mIndices[i];
- U16 idx2 = face.mIndices[i+1];
- U16 idx3 = face.mIndices[i+2];
-
- LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
- LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
- LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
-
- if (ll_is_degenerate(v1,v2,v3))
- {
- LL_WARNS() << "Degenerate face found!" << LL_ENDL;
- return false;
- }
- }*/
- return true;
+ return FALSE;
}
-bool validate_model(const LLModel* mdl)
+LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
{
- if (mdl->getNumVolumeFaces() == 0)
- {
- LL_WARNS() << "Model has no faces!" << LL_ENDL;
- return false;
- }
+ LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
- for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ if (texture)
{
- if (mdl->getVolumeFace(i).mNumVertices == 0)
- {
- LL_WARNS() << "Face has no vertices." << LL_ENDL;
- return false;
- }
-
- if (mdl->getVolumeFace(i).mNumIndices == 0)
+ if (texture->getDiscardLevel() > -1)
{
- LL_WARNS() << "Face has no indices." << LL_ENDL;
- return false;
- }
-
- if (!validate_face(mdl->getVolumeFace(i)))
- {
- return false;
+ gGL.getTexUnit(0)->bind(texture, true);
+ return texture;
}
}
- return true;
+ return NULL;
}
-BOOL stop_gloderror()
+std::string stripSuffix(std::string name)
{
- GLuint error = glodGetError();
-
- if (error != GLOD_NO_ERROR)
+ if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1))
{
- LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
- return TRUE;
+ return name.substr(0, name.rfind('_'));
}
-
- return FALSE;
+ return name;
}
-
LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
- : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
+: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
{
mMP = mp;
mLOD = lod;
@@ -393,6 +223,29 @@ void LLMeshFilePicker::notify(const std::string& filename)
mMP->loadModel(mFile, mLOD);
}
+void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut)
+{
+ LLModelLoader::scene::iterator base_iter = scene.begin();
+ bool found = false;
+ while (!found && (base_iter != scene.end()))
+ {
+ matOut = base_iter->first;
+
+ LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin();
+ while (!found && (base_instance_iter != base_iter->second.end()))
+ {
+ LLModelInstance& base_instance = *base_instance_iter++;
+ LLModel* base_model = base_instance.mModel;
+
+ if (base_model && (base_model->mLabel == name_to_match))
+ {
+ baseModelOut = base_model;
+ return;
+ }
+ }
+ base_iter++;
+ }
+}
//-----------------------------------------------------------------------------
// LLFloaterModelPreview()
@@ -613,6 +466,11 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option)
void LLFloaterModelPreview::loadModel(S32 lod)
{
mModelPreview->mLoading = true;
+ if (lod == LLModel::LOD_PHYSICS)
+ {
+ // loading physics from file
+ mModelPreview->mPhysicsSearchLOD = lod;
+ }
(new LLMeshFilePicker(mModelPreview, lod))->getFile();
}
@@ -791,9 +649,9 @@ void LLFloaterModelPreview::draw()
childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));
}
else
- if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
- {
- childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
+ if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL )
+ {
+ childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL)));
}
else
if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING )
@@ -945,9 +803,16 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
/*virtual*/
void LLFloaterModelPreview::onOpen(const LLSD& key)
{
+ LLModelPreview::sIgnoreLoadedCallback = false;
requestAgentUploadPermissions();
}
+/*virtual*/
+void LLFloaterModelPreview::onClose(bool app_quitting)
+{
+ LLModelPreview::sIgnoreLoadedCallback = true;
+}
+
//static
void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
{
@@ -1308,1815 +1173,6 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
}
//-----------------------------------------------------------------------------
-// LLModelLoader
-//-----------------------------------------------------------------------------
-LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
- std::deque<std::string>& jointsFromNodes )
-: mJointList( jointMap )
-, mJointsFromNode( jointsFromNodes )
-, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0)
-{
- mJointMap["mPelvis"] = "mPelvis";
- mJointMap["mTorso"] = "mTorso";
- mJointMap["mChest"] = "mChest";
- mJointMap["mNeck"] = "mNeck";
- mJointMap["mHead"] = "mHead";
- mJointMap["mSkull"] = "mSkull";
- mJointMap["mEyeRight"] = "mEyeRight";
- mJointMap["mEyeLeft"] = "mEyeLeft";
- mJointMap["mCollarLeft"] = "mCollarLeft";
- mJointMap["mShoulderLeft"] = "mShoulderLeft";
- mJointMap["mElbowLeft"] = "mElbowLeft";
- mJointMap["mWristLeft"] = "mWristLeft";
- mJointMap["mCollarRight"] = "mCollarRight";
- mJointMap["mShoulderRight"] = "mShoulderRight";
- mJointMap["mElbowRight"] = "mElbowRight";
- mJointMap["mWristRight"] = "mWristRight";
- mJointMap["mHipRight"] = "mHipRight";
- mJointMap["mKneeRight"] = "mKneeRight";
- mJointMap["mAnkleRight"] = "mAnkleRight";
- mJointMap["mFootRight"] = "mFootRight";
- mJointMap["mToeRight"] = "mToeRight";
- mJointMap["mHipLeft"] = "mHipLeft";
- mJointMap["mKneeLeft"] = "mKneeLeft";
- mJointMap["mAnkleLeft"] = "mAnkleLeft";
- mJointMap["mFootLeft"] = "mFootLeft";
- mJointMap["mToeLeft"] = "mToeLeft";
-
- mJointMap["avatar_mPelvis"] = "mPelvis";
- mJointMap["avatar_mTorso"] = "mTorso";
- mJointMap["avatar_mChest"] = "mChest";
- mJointMap["avatar_mNeck"] = "mNeck";
- mJointMap["avatar_mHead"] = "mHead";
- mJointMap["avatar_mSkull"] = "mSkull";
- mJointMap["avatar_mEyeRight"] = "mEyeRight";
- mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
- mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
- mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
- mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
- mJointMap["avatar_mWristLeft"] = "mWristLeft";
- mJointMap["avatar_mCollarRight"] = "mCollarRight";
- mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
- mJointMap["avatar_mElbowRight"] = "mElbowRight";
- mJointMap["avatar_mWristRight"] = "mWristRight";
- mJointMap["avatar_mHipRight"] = "mHipRight";
- mJointMap["avatar_mKneeRight"] = "mKneeRight";
- mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
- mJointMap["avatar_mFootRight"] = "mFootRight";
- mJointMap["avatar_mToeRight"] = "mToeRight";
- mJointMap["avatar_mHipLeft"] = "mHipLeft";
- mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
- mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
- mJointMap["avatar_mFootLeft"] = "mFootLeft";
- mJointMap["avatar_mToeLeft"] = "mToeLeft";
-
-
- mJointMap["hip"] = "mPelvis";
- mJointMap["abdomen"] = "mTorso";
- mJointMap["chest"] = "mChest";
- mJointMap["neck"] = "mNeck";
- mJointMap["head"] = "mHead";
- mJointMap["figureHair"] = "mSkull";
- mJointMap["lCollar"] = "mCollarLeft";
- mJointMap["lShldr"] = "mShoulderLeft";
- mJointMap["lForeArm"] = "mElbowLeft";
- mJointMap["lHand"] = "mWristLeft";
- mJointMap["rCollar"] = "mCollarRight";
- mJointMap["rShldr"] = "mShoulderRight";
- mJointMap["rForeArm"] = "mElbowRight";
- mJointMap["rHand"] = "mWristRight";
- mJointMap["rThigh"] = "mHipRight";
- mJointMap["rShin"] = "mKneeRight";
- mJointMap["rFoot"] = "mFootRight";
- mJointMap["lThigh"] = "mHipLeft";
- mJointMap["lShin"] = "mKneeLeft";
- mJointMap["lFoot"] = "mFootLeft";
-
- if (mPreview)
- {
- //only try to load from slm if viewer is configured to do so and this is the
- //initial model load (not an LoD or physics shape)
- mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
- mPreview->setLoadState(STARTING);
- }
- else
- {
- mTrySLM = false;
- }
-
- assert_main_thread();
- sActiveLoaderList.push_back(this) ;
-}
-
-LLModelLoader::~LLModelLoader()
-{
- assert_main_thread();
- sActiveLoaderList.remove(this);
-}
-
-void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
-{
- LLVector4a box[] =
- {
- LLVector4a(-1, 1,-1),
- LLVector4a(-1, 1, 1),
- LLVector4a(-1,-1,-1),
- LLVector4a(-1,-1, 1),
- LLVector4a( 1, 1,-1),
- LLVector4a( 1, 1, 1),
- LLVector4a( 1,-1,-1),
- LLVector4a( 1,-1, 1),
- };
-
- for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
- {
- const LLVolumeFace& face = model->getVolumeFace(j);
-
- LLVector4a center;
- center.setAdd(face.mExtents[0], face.mExtents[1]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(face.mExtents[1],face.mExtents[0]);
- size.mul(0.5f);
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector4a t;
- t.setMul(size, box[i]);
- t.add(center);
-
- LLVector4a v;
-
- mat.affineTransform(t, v);
-
- if (first_transform)
- {
- first_transform = FALSE;
- min = max = v;
- }
- else
- {
- update_min_max(min, max, v);
- }
- }
- }
-}
-
-void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
-{
- LLVector4a mina, maxa;
- LLMatrix4a mata;
-
- mata.loadu(mat);
- mina.load3(min.mV);
- maxa.load3(max.mV);
-
- stretch_extents(model, mata, mina, maxa, first_transform);
-
- min.set(mina.getF32ptr());
- max.set(maxa.getF32ptr());
-}
-
-void LLModelLoader::run()
-{
- doLoadModel();
- doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
-}
-
-bool LLModelLoader::doLoadModel()
-{
- //first, look for a .slm file of the same name that was modified later
- //than the .dae
-
- if (mTrySLM)
- {
- std::string filename = mFilename;
-
- std::string::size_type i = filename.rfind(".");
- if (i != std::string::npos)
- {
- filename.replace(i, filename.size()-1, ".slm");
- llstat slm_status;
- if (LLFile::stat(filename, &slm_status) == 0)
- { //slm file exists
- llstat dae_status;
- if (LLFile::stat(mFilename, &dae_status) != 0 ||
- dae_status.st_mtime < slm_status.st_mtime)
- {
- if (loadFromSLM(filename))
- { //slm successfully loaded, if this fails, fall through and
- //try loading from dae
-
- mLod = -1; //successfully loading from an slm implicitly sets all
- //LoDs
- return true;
- }
- }
- }
- }
- }
-
- //no suitable slm exists, load from the .dae file
- DAE dae;
- domCOLLADA* dom = dae.open(mFilename);
-
- if (!dom)
- {
- LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
- setLoadState( ERROR_PARSING );
- return false;
- }
- //Dom version
- daeString domVersion = dae.getDomVersion();
- std::string sldom(domVersion);
- LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL;
- //Dae version
- domVersionType docVersion = dom->getVersion();
- //0=1.4
- //1=1.4.1
- //2=Currently unsupported, however may work
- if (docVersion > 1 )
- {
- docVersion = VERSIONTYPE_COUNT;
- }
- LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL;
-
-
- daeDatabase* db = dae.getDatabase();
-
- daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
-
- daeDocument* doc = dae.getDoc(mFilename);
- if (!doc)
- {
- LL_WARNS() << "can't find internal doc" << LL_ENDL;
- return false;
- }
-
- daeElement* root = doc->getDomRoot();
- if (!root)
- {
- LL_WARNS() << "document has no root" << LL_ENDL;
- return false;
- }
-
- //Verify some basic properties of the dae
- //1. Basic validity check on controller
- U32 controllerCount = (int) db->getElementCount( NULL, "controller" );
- bool result = false;
- for ( int i=0; i<controllerCount; ++i )
- {
- domController* pController = NULL;
- db->getElement( (daeElement**) &pController, i , NULL, "controller" );
- result = mPreview->verifyController( pController );
- if (!result)
- {
- setLoadState( ERROR_PARSING );
- return true;
- }
- }
-
-
- //get unit scale
- mTransform.setIdentity();
-
- domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
-
- if (unit)
- {
- F32 meter = unit->getMeter();
- mTransform.mMatrix[0][0] = meter;
- mTransform.mMatrix[1][1] = meter;
- mTransform.mMatrix[2][2] = meter;
- }
-
- //get up axis rotation
- LLMatrix4 rotation;
-
- domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP
- domAsset::domUp_axis* up_axis =
- daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
-
- if (up_axis)
- {
- up = up_axis->getValue();
- }
-
- if (up == UPAXISTYPE_X_UP)
- {
- rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
- }
- else if (up == UPAXISTYPE_Y_UP)
- {
- rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
- }
-
- rotation *= mTransform;
- mTransform = rotation;
-
-
- for (daeInt idx = 0; idx < count; ++idx)
- { //build map of domEntities to LLModel
- domMesh* mesh = NULL;
- db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
-
- if (mesh)
- {
- LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
-
- if(model->getStatus() != LLModel::NO_ERRORS)
- {
- setLoadState(ERROR_PARSING + model->getStatus()) ;
- return false; //abort
- }
-
- if (model.notNull() && validate_model(model))
- {
- mModelList.push_back(model);
- mModel[mesh] = model;
- }
- }
- }
-
- count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
- for (daeInt idx = 0; idx < count; ++idx)
- { //add skinned meshes as instances
- domSkin* skin = NULL;
- db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
-
- if (skin)
- {
- domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
-
- if (geom)
- {
- domMesh* mesh = geom->getMesh();
- if (mesh)
- {
- LLModel* model = mModel[mesh];
- if (model)
- {
- LLVector3 mesh_scale_vector;
- LLVector3 mesh_translation_vector;
- model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
-
- LLMatrix4 normalized_transformation;
- normalized_transformation.setTranslation(mesh_translation_vector);
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= normalized_transformation;
- normalized_transformation = mesh_scale;
-
- glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
- inv_mat = inv_mat.inverse();
- LLMatrix4 inverse_normalized_transformation(inv_mat.m);
-
- domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
-
- if (bind_mat)
- { //get bind shape matrix
- domFloat4x4& dom_value = bind_mat->getValue();
-
- LLMeshSkinInfo& skin_info = model->mSkinInfo;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
- }
- }
-
- LLMatrix4 trans = normalized_transformation;
- trans *= skin_info.mBindShapeMatrix;
- skin_info.mBindShapeMatrix = trans;
- }
-
-
- //Some collada setup for accessing the skeleton
- daeElement* pElement = 0;
- dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
-
- //Try to get at the skeletal instance controller
- domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
- bool missingSkeletonOrScene = false;
-
- //If no skeleton, do a breadth-first search to get at specific joints
- bool rootNode = false;
-
- //Need to test for a skeleton that does not have a root node
- //This occurs when your instance controller does not have an associated scene
- if ( pSkeleton )
- {
- daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
- if ( pSkeletonRootNode )
- {
- rootNode = true;
- }
-
- }
- if ( !pSkeleton || !rootNode )
- {
- daeElement* pScene = root->getDescendant("visual_scene");
- if ( !pScene )
- {
- LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL;
- missingSkeletonOrScene = true;
- }
- else
- {
- //Get the children at this level
- daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
- S32 childCount = children.getCount();
-
- //Process any children that are joints
- //Not all children are joints, some code be ambient lights, cameras, geometry etc..
- for (S32 i = 0; i < childCount; ++i)
- {
- domNode* pNode = daeSafeCast<domNode>(children[i]);
- if ( isNodeAJoint( pNode ) )
- {
- processJointNode( pNode, mJointList );
- }
- }
- }
- }
- else
- //Has Skeleton
- {
- //Get the root node of the skeleton
- daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
- if ( pSkeletonRootNode )
- {
- //Once we have the root node - start acccessing it's joint components
- const int jointCnt = mJointMap.size();
- std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
-
- //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
- for ( int i=0; i<jointCnt; ++i, ++jointIt )
- {
- //Build a joint for the resolver to work with
- char str[64]={0};
- sprintf(str,"./%s",(*jointIt).first.c_str() );
- //LL_WARNS()<<"Joint "<< str <<LL_ENDL;
-
- //Setup the resolver
- daeSIDResolver resolver( pSkeletonRootNode, str );
-
- //Look for the joint
- domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
- if ( pJoint )
- {
- //Pull out the translate id and store it in the jointTranslations map
- daeSIDResolver jointResolverA( pJoint, "./translate" );
- domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
- daeSIDResolver jointResolverB( pJoint, "./location" );
- domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
-
- LLMatrix4 workingTransform;
-
- //Translation via SID
- if ( pTranslateA )
- {
- extractTranslation( pTranslateA, workingTransform );
- }
- else
- if ( pTranslateB )
- {
- extractTranslation( pTranslateB, workingTransform );
- }
- else
- {
- //Translation via child from element
- daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
- if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
- {
- LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
- missingSkeletonOrScene = true;
- }
- else
- if ( pTranslateElement )
- {
- extractTranslationViaElement( pTranslateElement, workingTransform );
- }
- else
- {
- extractTranslationViaSID( pJoint, workingTransform );
- }
-
- }
-
- //Store the joint transform w/respect to it's name.
- mJointList[(*jointIt).second.c_str()] = workingTransform;
- }
- }
-
- //If anything failed in regards to extracting the skeleton, joints or translation id,
- //mention it
- if ( missingSkeletonOrScene )
- {
- LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL;
- }
- }//got skeleton?
- }
-
-
- domSkin::domJoints* joints = skin->getJoints();
-
- domInputLocal_Array& joint_input = joints->getInput_array();
-
- for (size_t i = 0; i < joint_input.getCount(); ++i)
- {
- domInputLocal* input = joint_input.get(i);
- xsNMTOKEN semantic = input->getSemantic();
-
- if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
- { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
- daeElement* elem = input->getSource().getElement();
-
- domSource* source = daeSafeCast<domSource>(elem);
- if (source)
- {
-
-
- domName_array* names_source = source->getName_array();
-
- if (names_source)
- {
- domListOfNames &names = names_source->getValue();
-
- for (size_t j = 0; j < names.getCount(); ++j)
- {
- std::string name(names.get(j));
- if (mJointMap.find(name) != mJointMap.end())
- {
- name = mJointMap[name];
- }
- model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
- }
- }
- else
- {
- domIDREF_array* names_source = source->getIDREF_array();
- if (names_source)
- {
- xsIDREFS& names = names_source->getValue();
-
- for (size_t j = 0; j < names.getCount(); ++j)
- {
- std::string name(names.get(j).getID());
- if (mJointMap.find(name) != mJointMap.end())
- {
- name = mJointMap[name];
- }
- model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
- }
- }
- }
- }
- }
- else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
- { //found inv_bind_matrix array, fill model->mInvBindMatrix
- domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
- if (source)
- {
- domFloat_array* t = source->getFloat_array();
- if (t)
- {
- domListOfFloats& transform = t->getValue();
- S32 count = transform.getCount()/16;
-
- for (S32 k = 0; k < count; ++k)
- {
- LLMatrix4 mat;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- mat.mMatrix[i][j] = transform[k*16 + i + j*4];
- }
- }
-
- model->mSkinInfo.mInvBindMatrix.push_back(mat);
- }
- }
- }
- }
- }
-
- //Now that we've parsed the joint array, let's determine if we have a full rig
- //(which means we have all the joint sthat are required for an avatar versus
- //a skinned asset attached to a node in a file that contains an entire skeleton,
- //but does not use the skeleton).
- buildJointToNodeMappingFromScene( root );
- mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames );
-
- if ( !missingSkeletonOrScene )
- {
- //Set the joint translations on the avatar - if it's a full mapping
- //The joints are reset in the dtor
- if ( mPreview->getRigWithSceneParity() )
- {
- std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin();
- std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end();
- for (;masterJointIt!=masterJointItEnd;++masterJointIt )
- {
- std::string lookingForJoint = (*masterJointIt).first.c_str();
-
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
- {
- //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
- LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint );
- if ( pJoint )
- {
- LLUUID fake_mesh_id;
- fake_mesh_id.generate();
- pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString());
- }
- else
- {
- //Most likely an error in the asset.
- LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
- }
- }
- }
- }
- } //missingSkeletonOrScene
-
-
- //We need to construct the alternate bind matrix (which contains the new joint positions)
- //in the same order as they were stored in the joint buffer. The joints associated
- //with the skeleton are not stored in the same order as they are in the exported joint buffer.
- //This remaps the skeletal joints to be in the same order as the joints stored in the model.
- std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
- const int jointCnt = model->mSkinInfo.mJointNames.size();
- for ( int i=0; i<jointCnt; ++i, ++jointIt )
- {
- std::string lookingForJoint = (*jointIt).c_str();
- //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
- //and store it in the alternate bind matrix
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
- {
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
- LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
- newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
- model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
- }
- else
- {
- LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL;
- }
- }
-
- //grab raw position array
-
- domVertices* verts = mesh->getVertices();
- if (verts)
- {
- domInputLocal_Array& inputs = verts->getInput_array();
- for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
- {
- if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
- {
- domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
- if (pos_source)
- {
- domFloat_array* pos_array = pos_source->getFloat_array();
- if (pos_array)
- {
- domListOfFloats& pos = pos_array->getValue();
-
- for (size_t j = 0; j < pos.getCount(); j += 3)
- {
- if (pos.getCount() <= j+2)
- {
- LL_ERRS() << "Invalid position array size." << LL_ENDL;
- }
-
- LLVector3 v(pos[j], pos[j+1], pos[j+2]);
-
- //transform from COLLADA space to volume space
- v = v * inverse_normalized_transformation;
-
- model->mPosition.push_back(v);
- }
- }
- }
- }
- }
- }
-
- //grab skin weights array
- domSkin::domVertex_weights* weights = skin->getVertex_weights();
- if (weights)
- {
- domInputLocalOffset_Array& inputs = weights->getInput_array();
- domFloat_array* vertex_weights = NULL;
- for (size_t i = 0; i < inputs.getCount(); ++i)
- {
- if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
- {
- domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
- if (weight_source)
- {
- vertex_weights = weight_source->getFloat_array();
- }
- }
- }
-
- if (vertex_weights)
- {
- domListOfFloats& w = vertex_weights->getValue();
- domListOfUInts& vcount = weights->getVcount()->getValue();
- domListOfInts& v = weights->getV()->getValue();
-
- U32 c_idx = 0;
- for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
- { //for each vertex
- daeUInt count = vcount[vc_idx];
-
- //create list of weights that influence this vertex
- LLModel::weight_list weight_list;
-
- for (daeUInt i = 0; i < count; ++i)
- { //for each weight
- daeInt joint_idx = v[c_idx++];
- daeInt weight_idx = v[c_idx++];
-
- if (joint_idx == -1)
- {
- //ignore bindings to bind_shape_matrix
- continue;
- }
-
- F32 weight_value = w[weight_idx];
-
- weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
- }
-
- //sort by joint weight
- std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
-
- std::vector<LLModel::JointWeight> wght;
-
- F32 total = 0.f;
-
- for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
- { //take up to 4 most significant weights
- if (weight_list[i].mWeight > 0.f)
- {
- wght.push_back( weight_list[i] );
- total += weight_list[i].mWeight;
- }
- }
-
- F32 scale = 1.f/total;
- if (scale != 1.f)
- { //normalize weights
- for (U32 i = 0; i < wght.size(); ++i)
- {
- wght[i].mWeight *= scale;
- }
- }
-
- model->mSkinWeights[model->mPosition[vc_idx]] = wght;
- }
-
- //add instance to scene for this model
-
- LLMatrix4 transformation = mTransform;
- // adjust the transformation to compensate for mesh normalization
-
- LLMatrix4 mesh_translation;
- mesh_translation.setTranslation(mesh_translation_vector);
- mesh_translation *= transformation;
- transformation = mesh_translation;
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= transformation;
- transformation = mesh_scale;
-
- std::map<std::string, LLImportMaterial> materials;
- for (U32 i = 0; i < model->mMaterialList.size(); ++i)
- {
- materials[model->mMaterialList[i]] = LLImportMaterial();
- }
- mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
- stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
- }
- }
- }
- }
- }
- }
- }
-
- daeElement* scene = root->getDescendant("visual_scene");
-
- if (!scene)
- {
- LL_WARNS() << "document has no visual_scene" << LL_ENDL;
- setLoadState( ERROR_PARSING );
- return true;
- }
-
- setLoadState( DONE );
-
- bool badElement = false;
-
- processElement( scene, badElement );
-
- if ( badElement )
- {
- setLoadState( ERROR_PARSING );
- }
-
- return true;
-}
-
-void LLModelLoader::setLoadState(U32 state)
-{
- if (mPreview)
- {
- mPreview->setLoadState(state);
- }
-}
-
-bool LLModelLoader::loadFromSLM(const std::string& filename)
-{
- //only need to populate mScene with data from slm
- llstat stat;
-
- if (LLFile::stat(filename, &stat))
- { //file does not exist
- return false;
- }
-
- S32 file_size = (S32) stat.st_size;
-
- llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
- LLSD data;
- LLSDSerialize::fromBinary(data, ifstream, file_size);
- ifstream.close();
-
- //build model list for each LoD
- model_list model[LLModel::NUM_LODS];
-
- if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
- { //unsupported version
- return false;
- }
-
- LLSD& mesh = data["mesh"];
-
- LLVolumeParams volume_params;
- volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-
- for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- for (U32 i = 0; i < mesh.size(); ++i)
- {
- std::stringstream str(mesh[i].asString());
- LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
- if (loaded_model->loadModel(str))
- {
- loaded_model->mLocalID = i;
- model[lod].push_back(loaded_model);
-
- if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
- {
- //check to see if rig is valid
- mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
- }
- }
- }
- }
-
- if (model[LLModel::LOD_HIGH].empty())
- { //failed to load high lod
- return false;
- }
-
- // Set name.
- std::string name = data["name"];
- if (!name.empty())
- {
- model[LLModel::LOD_HIGH][0]->mLabel = name;
- }
-
-
- //load instance list
- model_instance_list instance_list;
-
- LLSD& instance = data["instance"];
-
- for (U32 i = 0; i < instance.size(); ++i)
- {
- //deserialize instance list
- instance_list.push_back(LLModelInstance(instance[i]));
-
- //match up model instance pointers
- S32 idx = instance_list[i].mLocalMeshID;
-
- for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- if (!model[lod].empty())
- {
- instance_list[i].mLOD[lod] = model[lod][idx];
- }
- }
-
- instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
- }
-
-
- //convert instance_list to mScene
- mFirstTransform = TRUE;
- for (U32 i = 0; i < instance_list.size(); ++i)
- {
- LLModelInstance& cur_instance = instance_list[i];
- mScene[cur_instance.mTransform].push_back(cur_instance);
- stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
- }
-
- setLoadState( DONE );
-
- return true;
-}
-
-//static
-bool LLModelLoader::isAlive(LLModelLoader* loader)
-{
- if(!loader)
- {
- return false ;
- }
-
- std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
- for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
-
- return *iter == loader ;
-}
-
-void LLModelLoader::loadModelCallback()
-{
- assert_main_thread();
-
- if (mPreview)
- {
- mPreview->loadModelCallback(mLod);
- }
-
- while (!isStopped())
- { //wait until this thread is stopped before deleting self
- apr_sleep(100);
- }
-
- //doubel check if "this" is valid before deleting it, in case it is aborted during running.
- if(!isAlive(this))
- {
- return ;
- }
-
- //cleanup model loader
- if (mPreview)
- {
- mPreview->mModelLoader = NULL;
- }
-
- delete this;
-}
-//-----------------------------------------------------------------------------
-// buildJointToNodeMappingFromScene()
-//-----------------------------------------------------------------------------
-void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot )
-{
- daeElement* pScene = pRoot->getDescendant("visual_scene");
- if ( pScene )
- {
- daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
- S32 childCount = children.getCount();
- for (S32 i = 0; i < childCount; ++i)
- {
- domNode* pNode = daeSafeCast<domNode>(children[i]);
- processJointToNodeMapping( pNode );
- }
- }
-}
-//-----------------------------------------------------------------------------
-// processJointToNodeMapping()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processJointToNodeMapping( domNode* pNode )
-{
- if ( isNodeAJoint( pNode ) )
- {
- //1.Store the parent
- std::string nodeName = pNode->getName();
- if ( !nodeName.empty() )
- {
- mJointsFromNode.push_front( pNode->getName() );
- }
- //2. Handle the kiddo's
- processChildJoints( pNode );
- }
- else
- {
- //Determine if the're any children wrt to this failed node.
- //This occurs when an armature is exported and ends up being what essentially amounts to
- //as the root for the visual_scene
- if ( pNode )
- {
- processChildJoints( pNode );
- }
- else
- {
- LL_INFOS()<<"Node is NULL"<<LL_ENDL;
- }
-
- }
-}
-//-----------------------------------------------------------------------------
-// processChildJoint()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processChildJoints( domNode* pParentNode )
-{
- daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren();
- S32 childOfChildCount = childOfChild.getCount();
- for (S32 i = 0; i < childOfChildCount; ++i)
- {
- domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
- if ( pChildNode )
- {
- processJointToNodeMapping( pChildNode );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// critiqueRigForUploadApplicability()
-//-----------------------------------------------------------------------------
-void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
-{
- critiqueJointToNodeMappingFromScene();
-
- //Determines the following use cases for a rig:
- //1. It is suitable for upload with skin weights & joint positions, or
- //2. It is suitable for upload as standard av with just skin weights
-
- bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
- bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
-
- //It's OK that both could end up being true, both default to false
- if ( isJointPositionUploadOK )
- {
- setRigValidForJointPositionUpload( true );
- }
-
- if ( isRigLegacyOK)
- {
- setLegacyRigValid( true );
- }
-
-}
-//-----------------------------------------------------------------------------
-// critiqueJointToNodeMappingFromScene()
-//-----------------------------------------------------------------------------
-void LLModelPreview::critiqueJointToNodeMappingFromScene( void )
-{
- //Do the actual nodes back the joint listing from the dae?
- //if yes then this is a fully rigged asset, otherwise it's just a partial rig
-
- std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin();
- std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end();
- bool result = true;
-
- if ( !mJointsFromNode.empty() )
- {
- for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
- {
- std::string name = *jointsFromNodeIt;
- if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
- {
- continue;
- }
- else
- {
- LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL;
- result = false;
- }
- }
- }
- else
- {
- result = false;
- }
-
- //Determines the following use cases for a rig:
- //1. Full av rig w/1-1 mapping from the scene and joint array
- //2. Partial rig but w/o parity between the scene and joint array
- if ( result )
- {
- setRigWithSceneParity( true );
- }
-}
-//-----------------------------------------------------------------------------
-// isRigLegacy()
-//-----------------------------------------------------------------------------
-bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
-{
- //No joints in asset
- if ( jointListFromAsset.size() == 0 )
- {
- return false;
- }
-
- bool result = false;
-
- std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
- std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
-
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
-}
-//-----------------------------------------------------------------------------
-// isRigSuitableForJointPositionUpload()
-//-----------------------------------------------------------------------------
-bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
-{
- bool result = false;
-
- std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();
- std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
-
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
-}
-
-
-//called in the main thread
-void LLModelLoader::loadTextures()
-{
- BOOL is_paused = isPaused() ;
- pause() ; //pause the loader
-
- for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
- {
- for(U32 i = 0 ; i < iter->second.size(); i++)
- {
- for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
- j != iter->second[i].mMaterial.end(); ++j)
- {
- LLImportMaterial& material = j->second;
-
- if(!material.mDiffuseMapFilename.empty())
- {
- material.mDiffuseMap =
- LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
- material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
- material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX);
- mNumOfFetchingTextures++ ;
- }
- }
- }
- }
-
- if(!is_paused)
- {
- unpause() ;
- }
-}
-
-//-----------------------------------------------------------------------------
-// isNodeAJoint()
-//-----------------------------------------------------------------------------
-bool LLModelLoader::isNodeAJoint( domNode* pNode )
-{
- if ( !pNode )
- {
- LL_INFOS()<<"Created node is NULL"<<LL_ENDL;
- return false;
- }
-
- if ( pNode->getName() == NULL )
- {
- LL_INFOS()<<"Parsed node has no name "<<LL_ENDL;
- //Attempt to write the node id, if possible (aids in debugging the visual scene)
- if ( pNode->getId() )
- {
- LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL;
- }
- return false;
- }
-
- if ( mJointMap.find( pNode->getName() ) != mJointMap.end() )
- {
- return true;
- }
-
- return false;
-}
-//-----------------------------------------------------------------------------
-// verifyCount
-//-----------------------------------------------------------------------------
-bool LLModelPreview::verifyCount( int expected, int result )
-{
- if ( expected != result )
- {
- LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL;
- return false;
- }
- return true;
-}
-//-----------------------------------------------------------------------------
-// verifyController
-//-----------------------------------------------------------------------------
-bool LLModelPreview::verifyController( domController* pController )
-{
-
- bool result = true;
-
- domSkin* pSkin = pController->getSkin();
-
- if ( pSkin )
- {
- xsAnyURI & uri = pSkin->getSource();
- domElement* pElement = uri.getElement();
-
- if ( !pElement )
- {
- LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL;
- return false;
- }
-
- daeString type_str = pElement->getTypeName();
- if ( stricmp(type_str, "geometry") == 0 )
- {
- //Skin is reference directly by geometry and get the vertex count from skin
- domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights();
- U32 vertexWeightsCount = pVertexWeights->getCount();
- domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement();
- domMesh* pMesh = pGeometry->getMesh();
-
- if ( pMesh )
- {
- //Get vertex count from geometry
- domVertices* pVertices = pMesh->getVertices();
- if ( !pVertices )
- {
- LL_INFOS()<<"No vertices!"<<LL_ENDL;
- return false;
- }
-
- if ( pVertices )
- {
- xsAnyURI src = pVertices->getInput_array()[0]->getSource();
- domSource* pSource = (domSource*) (domElement*) src.getElement();
- U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount();
- result = verifyCount( verticesCount, vertexWeightsCount );
- if ( !result )
- {
- return result;
- }
- }
- }
-
- U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount();
- result = verifyCount( vcountCount, vertexWeightsCount );
- if ( !result )
- {
- return result;
- }
-
- domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array();
- U32 sum = 0;
- for (size_t i=0; i<vcountCount; i++)
- {
- sum += pVertexWeights->getVcount()->getValue()[i];
- }
- result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() );
- }
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// extractTranslation()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
-{
- domFloat3 jointTrans = pTranslate->getValue();
- LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
- transform.setTranslation( singleJointTranslation );
-}
-//-----------------------------------------------------------------------------
-// extractTranslationViaElement()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
-{
- if ( pTranslateElement )
- {
- domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
- domFloat3 translateChild = pTranslateChild->getValue();
- LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
- transform.setTranslation( singleJointTranslation );
- }
-}
-//-----------------------------------------------------------------------------
-// extractTranslationViaSID()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform )
-{
- if ( pElement )
- {
- daeSIDResolver resolver( pElement, "./transform" );
- domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() );
- //We are only extracting out the translational component atm
- LLMatrix4 workingTransform;
- if ( pMatrix )
- {
- domFloat4x4 domArray = pMatrix->getValue();
- for ( int i = 0; i < 4; i++ )
- {
- for( int j = 0; j < 4; j++ )
- {
- workingTransform.mMatrix[i][j] = domArray[i + j*4];
- }
- }
- LLVector3 trans = workingTransform.getTranslation();
- transform.setTranslation( trans );
- }
- }
- else
- {
- LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL;
- }
-}
-//-----------------------------------------------------------------------------
-// processJointNode()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms )
-{
- if (pNode->getName() == NULL)
- {
- LL_WARNS() << "nameless node, can't process" << LL_ENDL;
- return;
- }
-
- //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL;
-
- //1. handle the incoming node - extract out translation via SID or element
-
- LLMatrix4 workingTransform;
-
- //Pull out the translate id and store it in the jointTranslations map
- daeSIDResolver jointResolverA( pNode, "./translate" );
- domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
- daeSIDResolver jointResolverB( pNode, "./location" );
- domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
-
- //Translation via SID was successful
- if ( pTranslateA )
- {
- extractTranslation( pTranslateA, workingTransform );
- }
- else
- if ( pTranslateB )
- {
- extractTranslation( pTranslateB, workingTransform );
- }
- else
- {
- //Translation via child from element
- daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
- if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
- {
- //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
- daeSIDResolver jointResolver( pNode, "./matrix" );
- domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
- if ( pMatrix )
- {
- //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
- domFloat4x4 domArray = pMatrix->getValue();
- for ( int i = 0; i < 4; i++ )
- {
- for( int j = 0; j < 4; j++ )
- {
- workingTransform.mMatrix[i][j] = domArray[i + j*4];
- }
- }
- }
- else
- {
- LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL;
- }
- }
- else
- {
- extractTranslationViaElement( pTranslateElement, workingTransform );
- }
- }
-
- //Store the working transform relative to the nodes name.
- jointTransforms[ pNode->getName() ] = workingTransform;
-
- //2. handle the nodes children
-
- //Gather and handle the incoming nodes children
- daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
- S32 childOfChildCount = childOfChild.getCount();
-
- for (S32 i = 0; i < childOfChildCount; ++i)
- {
- domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
- if ( pChildNode )
- {
- processJointNode( pChildNode, jointTransforms );
- }
- }
-}
-//-----------------------------------------------------------------------------
-// getChildFromElement()
-//-----------------------------------------------------------------------------
-daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name )
-{
- daeElement* pChildOfElement = pElement->getChild( name.c_str() );
- if ( pChildOfElement )
- {
- return pChildOfElement;
- }
- LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
- return NULL;
-}
-
-void LLModelLoader::processElement( daeElement* element, bool& badElement )
-{
- LLMatrix4 saved_transform = mTransform;
-
- domTranslate* translate = daeSafeCast<domTranslate>(element);
- if (translate)
- {
- domFloat3 dom_value = translate->getValue();
-
- LLMatrix4 translation;
- translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
-
- translation *= mTransform;
- mTransform = translation;
- }
-
- domRotate* rotate = daeSafeCast<domRotate>(element);
- if (rotate)
- {
- domFloat4 dom_value = rotate->getValue();
-
- LLMatrix4 rotation;
- rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
-
- rotation *= mTransform;
- mTransform = rotation;
- }
-
- domScale* scale = daeSafeCast<domScale>(element);
- if (scale)
- {
- domFloat3 dom_value = scale->getValue();
-
-
- LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]);
- scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes
- LLMatrix4 scaling;
- scaling.initScale(scale_vector);
-
- scaling *= mTransform;
- mTransform = scaling;
- }
-
- domMatrix* matrix = daeSafeCast<domMatrix>(element);
- if (matrix)
- {
- domFloat4x4 dom_value = matrix->getValue();
-
- LLMatrix4 matrix_transform;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
- }
- }
-
- matrix_transform *= mTransform;
- mTransform = matrix_transform;
- }
-
- domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
- if (instance_geo)
- {
- domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
- if (geo)
- {
- domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
- if (mesh)
- {
- LLModel* model = mModel[mesh];
- if (model)
- {
- LLMatrix4 transformation = mTransform;
-
- if (mTransform.determinant() < 0)
- { //negative scales are not supported
- LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL;
- badElement = true;
- }
-
- std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo);
-
- // adjust the transformation to compensate for mesh normalization
- LLVector3 mesh_scale_vector;
- LLVector3 mesh_translation_vector;
- model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
-
- LLMatrix4 mesh_translation;
- mesh_translation.setTranslation(mesh_translation_vector);
- mesh_translation *= transformation;
- transformation = mesh_translation;
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= transformation;
- transformation = mesh_scale;
-
- std::string label = getElementLabel(instance_geo);
- mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
-
- stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
- }
- }
- }
- else
- {
- LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
- badElement = true;
- }
-
- }
-
- domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
- if (instance_node)
- {
- daeElement* instance = instance_node->getUrl().getElement();
- if (instance)
- {
- processElement(instance,badElement);
- }
- }
-
- //process children
- daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
- int childCount = children.getCount();
- for (S32 i = 0; i < childCount; i++)
- {
- processElement(children[i],badElement);
- }
-
- domNode* node = daeSafeCast<domNode>(element);
- if (node)
- { //this element was a node, restore transform before processiing siblings
- mTransform = saved_transform;
- }
-}
-
-std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
-{
- std::map<std::string, LLImportMaterial> materials;
- for (int i = 0; i < model->mMaterialList.size(); i++)
- {
- LLImportMaterial import_material;
-
- domInstance_material* instance_mat = NULL;
-
- domBind_material::domTechnique_common* technique =
- daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
-
- if (technique)
- {
- daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
- for (int j = 0; j < inst_materials.getCount(); j++)
- {
- std::string symbol(inst_materials[j]->getSymbol());
-
- if (symbol == model->mMaterialList[i]) // found the binding
- {
- instance_mat = inst_materials[j];
- }
- }
- }
-
- if (instance_mat)
- {
- domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
- if (material)
- {
- domInstance_effect* instance_effect =
- daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
- if (instance_effect)
- {
- domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
- if (effect)
- {
- domProfile_COMMON* profile =
- daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
- if (profile)
- {
- import_material = profileToMaterial(profile);
- }
- }
- }
- }
- }
-
- import_material.mBinding = model->mMaterialList[i];
- materials[model->mMaterialList[i]] = import_material;
- }
-
- return materials;
-}
-
-LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material)
-{
- LLImportMaterial mat;
- mat.mFullbright = FALSE;
-
- daeElement* diffuse = material->getDescendant("diffuse");
- if (diffuse)
- {
- domCommon_color_or_texture_type_complexType::domTexture* texture =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
- if (texture)
- {
- domCommon_newparam_type_Array newparams = material->getNewparam_array();
- for (S32 i = 0; i < newparams.getCount(); i++)
- {
- domFx_surface_common* surface = newparams[i]->getSurface();
- if (surface)
- {
- domFx_surface_init_common* init = surface->getFx_surface_init_common();
- if (init)
- {
- domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
-
- if (init_from.getCount() > i)
- {
- domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
- if (image)
- {
- // we only support init_from now - embedded data will come later
- domImage::domInit_from* init = image->getInit_from();
- if (init)
- {
- mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
- mat.mDiffuseMapLabel = getElementLabel(material);
- }
- }
- }
- }
- }
- }
- }
-
- domCommon_color_or_texture_type_complexType::domColor* color =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
- if (color)
- {
- domFx_color_common domfx_color = color->getValue();
- LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
- mat.mDiffuseColor = value;
- }
- }
-
- daeElement* emission = material->getDescendant("emission");
- if (emission)
- {
- LLColor4 emission_color = getDaeColor(emission);
- if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
- {
- mat.mFullbright = TRUE;
- }
- }
-
- return mat;
-}
-
-// try to get a decent label for this element
-std::string LLModelLoader::getElementLabel(daeElement *element)
-{
- // if we have a name attribute, use it
- std::string name = element->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if we have an ID attribute, use it
- if (element->getID())
- {
- return std::string(element->getID());
- }
-
- // if we have a parent, use it
- daeElement* parent = element->getParent();
- if (parent)
- {
- // if parent has a name, use it
- std::string name = parent->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if parent has an ID, use it
- if (parent->getID())
- {
- return std::string(parent->getID());
- }
- }
-
- // try to use our type
- daeString element_name = element->getElementName();
- if (element_name)
- {
- return std::string(element_name);
- }
-
- // if all else fails, use "object"
- return std::string("object");
-}
-
-LLColor4 LLModelLoader::getDaeColor(daeElement* element)
-{
- LLColor4 value;
- domCommon_color_or_texture_type_complexType::domColor* color =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
- if (color)
- {
- domFx_color_common domfx_color = color->getValue();
- value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
- }
-
- return value;
-}
-
-//-----------------------------------------------------------------------------
// LLModelPreview
//-----------------------------------------------------------------------------
@@ -3125,7 +1181,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mPelvisZOffset( 0.0f )
, mLegacyRigValid( false )
, mRigValidJointUpload( false )
+, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
+, mModelNoErrors( true )
, mRigParityWithScene( false )
, mLastJointUpdate( false )
{
@@ -3170,51 +1228,20 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
glodInit();
- //move into joint mapper class
- //1. joints for joint offset verification
- mMasterJointList.push_front("mPelvis");
- mMasterJointList.push_front("mTorso");
- mMasterJointList.push_front("mChest");
- mMasterJointList.push_front("mNeck");
- mMasterJointList.push_front("mHead");
- mMasterJointList.push_front("mCollarLeft");
- mMasterJointList.push_front("mShoulderLeft");
- mMasterJointList.push_front("mElbowLeft");
- mMasterJointList.push_front("mWristLeft");
- mMasterJointList.push_front("mCollarRight");
- mMasterJointList.push_front("mShoulderRight");
- mMasterJointList.push_front("mElbowRight");
- mMasterJointList.push_front("mWristRight");
- mMasterJointList.push_front("mHipRight");
- mMasterJointList.push_front("mKneeRight");
- mMasterJointList.push_front("mFootRight");
- mMasterJointList.push_front("mHipLeft");
- mMasterJointList.push_front("mKneeLeft");
- mMasterJointList.push_front("mFootLeft");
- //2. legacy joint list - used to verify rigs that will not be using joint offsets
- mMasterLegacyJointList.push_front("mPelvis");
- mMasterLegacyJointList.push_front("mTorso");
- mMasterLegacyJointList.push_front("mChest");
- mMasterLegacyJointList.push_front("mNeck");
- mMasterLegacyJointList.push_front("mHead");
- mMasterLegacyJointList.push_front("mHipRight");
- mMasterLegacyJointList.push_front("mKneeRight");
- mMasterLegacyJointList.push_front("mFootRight");
- mMasterLegacyJointList.push_front("mHipLeft");
- mMasterLegacyJointList.push_front("mKneeLeft");
- mMasterLegacyJointList.push_front("mFootLeft");
-
createPreviewAvatar();
}
LLModelPreview::~LLModelPreview()
{
- if (mModelLoader)
- {
- mModelLoader->mPreview = NULL;
- mModelLoader = NULL;
- }
- //*HACK : *TODO : turn this back on when we understand why this crashes
+ // glod apparently has internal mem alignment issues that are angering
+ // the heap-check code in windows, these should be hunted down in that
+ // TP code, if possible
+ //
+ // kernel32.dll!HeapFree() + 0x14 bytes
+ // msvcr100.dll!free(void * pBlock) Line 51 C
+ // glod.dll!glodGetGroupParameteriv() + 0x119 bytes
+ // glod.dll!glodShutdown() + 0x77 bytes
+ //
//glodShutdown();
}
@@ -3284,7 +1311,9 @@ U32 LLModelPreview::calcResourceCost()
decomp,
mFMP->childGetValue("upload_skin").asBoolean(),
mFMP->childGetValue("upload_joints").asBoolean(),
- TRUE);
+ TRUE,
+ FALSE,
+ instance.mModel->mSubmodelID);
num_hulls += decomp.mHull.size();
for (U32 i = 0; i < decomp.mHull.size(); ++i)
@@ -3351,29 +1380,12 @@ void LLModelPreview::rebuildUploadData()
F32 max_scale = 0.f;
- //reorder materials to match mBaseModel
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- if (mBaseModel.size() == mModel[i].size())
- {
- for (U32 j = 0; j < mBaseModel.size(); ++j)
- {
-
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
-
- if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
- {
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
- }
- }
- }
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
{ //for each transform in scene
- LLMatrix4 mat = iter->first;
+ LLMatrix4 mat = iter->first;
// compute position
LLVector3 position = LLVector3(0, 0, 0) * mat;
@@ -3390,38 +1402,171 @@ void LLModelPreview::rebuildUploadData()
mat *= scale_mat;
- for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
- { //for each instance with said transform applied
- LLModelInstance instance = *model_iter;
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();)
+ { //for each instance with said transform applied
+ LLModelInstance instance = *model_iter++;
LLModel* base_model = instance.mModel;
- if (base_model)
+ if (base_model && !requested_name.empty())
{
base_model->mRequestedLabel = requested_name;
base_model->mMetric = metric;
}
- S32 idx = 0;
- for (idx = 0; idx < mBaseModel.size(); ++idx)
- { //find reference instance for this model
- if (mBaseModel[idx] == base_model)
+ for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--)
+ {
+ LLModel* lod_model = NULL;
+ if (!legacyMatching)
{
- break;
+ // Fill LOD slots by finding matching meshes by label with name extensions
+ // in the appropriate scene for each LOD. This fixes all kinds of issues
+ // where the indexed method below fails in spectacular fashion.
+ // If you don't take the time to name your LOD and PHYS meshes
+ // with the name of their corresponding mesh in the HIGH LOD,
+ // then the indexed method will be attempted below.
+
+ LLMatrix4 transform;
+
+ std::string name_to_match = instance.mLabel;
+ llassert(!name_to_match.empty());
+
+ int extensionLOD;
+ if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty())
+ {
+ extensionLOD = i;
+ }
+ else
+ {
+ //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for
+ extensionLOD = mPhysicsSearchLOD;
+ }
+
+ std::string toAdd;
+ switch (extensionLOD)
+ {
+ case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
+ case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (name_to_match.find(toAdd) == -1)
+ {
+ name_to_match += toAdd;
+ }
+
+ FindModel(mScene[i], name_to_match, lod_model, transform);
+
+ if (!lod_model && i != LLModel::LOD_PHYSICS)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL;
+ }
+
+ int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i;
+ while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model)
+ {
+ std::string name_to_match = instance.mLabel;
+ llassert(!name_to_match.empty());
+
+ std::string toAdd;
+ switch (searchLOD)
+ {
+ case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
+ case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (name_to_match.find(toAdd) == -1)
+ {
+ name_to_match += toAdd;
+ }
+
+ // See if we can find an appropriately named model in LOD 'searchLOD'
+ //
+ FindModel(mScene[searchLOD], name_to_match, lod_model, transform);
+ searchLOD++;
+ }
+ }
}
- }
+ else
+ {
+ // Use old method of index-based association
+ U32 idx = 0;
+ for (idx = 0; idx < mBaseModel.size(); ++idx)
+ {
+ // find reference instance for this model
+ if (mBaseModel[idx] == base_model)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL;
+ }
+ break;
+ }
+ }
- if(idx < mBaseModel.size())
- {
- for (U32 i = 0; i < LLModel::NUM_LODS; i++)
- { //fill LOD slots based on reference model index
+ // If the model list for the current LOD includes that index...
+ //
if (mModel[i].size() > idx)
{
- instance.mLOD[i] = mModel[i][idx];
+ // Assign that index from the model list for our LOD as the LOD model for this instance
+ //
+ lod_model = mModel[i][idx];
+ if (importerDebug)
+ {
+ LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL;
+ }
}
- else
+ else if (importerDebug)
{
- instance.mLOD[i] = NULL;
+ LL_INFOS() << "List of models does not include index " << idx << LL_ENDL;
+ }
+ }
+
+ if (lod_model)
+ {
+ if (importerDebug)
+ {
+ if (i == LLModel::LOD_PHYSICS)
+ {
+ LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL;
+ }
+ }
+ instance.mLOD[i] = lod_model;
+ }
+ else if (importerDebug)
+ {
+ LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL;
+ }
+ }
+
+ LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH];
+ if (!high_lod_model)
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+ else
+ {
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+ llassert(instance.mLOD[i]);
+ if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) )
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
}
}
}
@@ -3430,6 +1575,34 @@ void LLModelPreview::rebuildUploadData()
}
}
+ for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++)
+ {
+ // Search for models that are not included into upload data
+ // If we found any, that means something we loaded is not a sub-model.
+ for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind)
+ {
+ bool found_model = false;
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ {
+ LLModelInstance& instance = *iter;
+ if (instance.mLOD[lod] == mModel[lod][model_ind])
+ {
+ found_model = true;
+ break;
+ }
+ }
+ if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL;
+ }
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+ }
+ }
+
F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale;
F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]);
@@ -3496,7 +1669,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
meshes.insert(instance.mModel);
std::stringstream str;
-
LLModel::Decomposition& decomp =
instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?
instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
@@ -3509,8 +1681,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
instance.mLOD[LLModel::LOD_LOW],
instance.mLOD[LLModel::LOD_IMPOSTOR],
decomp,
- save_skinweights, save_joint_positions, FALSE, TRUE);
-
+ save_skinweights, save_joint_positions,
+ FALSE, TRUE, instance.mModel->mSubmodelID);
data["mesh"][instance.mModel->mLocalID] = str.str();
}
@@ -3578,13 +1750,28 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
clearGLODGroup();
}
- mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );
+ mModelLoader = new LLDAELoader(
+ filename,
+ lod,
+ &LLModelPreview::loadedCallback,
+ &LLModelPreview::lookupJointByName,
+ &LLModelPreview::loadTextures,
+ &LLModelPreview::stateChangedCallback,
+ this,
+ mJointTransformMap,
+ mJointsFromNode,
+ gSavedSettings.getU32("ImporterModelLimit"));
if (force_disable_slm)
{
mModelLoader->mTrySLM = false;
}
-
+ else
+ {
+ //only try to load from slm if viewer is configured to do so and this is the
+ //initial model load (not an LoD or physics shape)
+ mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty();
+ }
mModelLoader->start();
mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
@@ -3615,6 +1802,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)
if (lod >= 0 && lod <= 3)
{
+ mPhysicsSearchLOD = lod;
mModel[LLModel::LOD_PHYSICS] = mModel[lod];
mScene[LLModel::LOD_PHYSICS] = mScene[lod];
mLODFile[LLModel::LOD_PHYSICS].clear();
@@ -3634,11 +1822,14 @@ void LLModelPreview::clearIncompatible(S32 lod)
return;
}
+ // at this point we don't care about sub-models,
+ // different amount of sub-models means face count mismatch, not incompatibility
+ U32 lod_size = countRootModels(mModel[lod]);
for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
{ //clear out any entries that aren't compatible with this model
if (i != lod)
{
- if (mModel[i].size() != mModel[lod].size())
+ if (countRootModels(mModel[i]) != lod_size)
{
mModel[i].clear();
mScene[i].clear();
@@ -3673,7 +1864,7 @@ void LLModelPreview::clearGLODGroup()
}
}
-void LLModelPreview::loadModelCallback(S32 lod)
+void LLModelPreview::loadModelCallback(S32 loaded_lod)
{
assert_main_thread();
@@ -3686,12 +1877,18 @@ void LLModelPreview::loadModelCallback(S32 lod)
if(getLoadState() >= LLModelLoader::ERROR_PARSING)
{
mLoading = false ;
+ mModelLoader = NULL;
return ;
}
+ // Copy determinations about rig so UI will reflect them
+ //
+ setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
+ setLegacyRigValid(mModelLoader->isLegacyRigValid());
+
mModelLoader->loadTextures() ;
- if (lod == -1)
+ if (loaded_lod == -1)
{ //populate all LoDs from model loader scene
mBaseModel.clear();
mBaseScene.clear();
@@ -3723,6 +1920,11 @@ void LLModelPreview::loadModelCallback(S32 lod)
//override displayed model with current LoD
list_iter->mModel = list_iter->mLOD[lod];
+ if (!list_iter->mModel)
+ {
+ continue;
+ }
+
//add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)
S32 idx = list_iter->mModel->mLocalID;
@@ -3731,7 +1933,7 @@ void LLModelPreview::loadModelCallback(S32 lod)
mModel[lod].resize(idx+1);
}
- mModel[lod][idx] = list_iter->mModel;
+ mModel[lod][idx] = list_iter->mModel;
if (!list_iter->mModel->mSkinWeights.empty())
{
skin_weights = true;
@@ -3774,31 +1976,108 @@ void LLModelPreview::loadModelCallback(S32 lod)
}
else
{ //only replace given LoD
- mModel[lod] = mModelLoader->mModelList;
- mScene[lod] = mModelLoader->mScene;
- mVertexBuffer[lod].clear();
+ mModel[loaded_lod] = mModelLoader->mModelList;
+ mScene[loaded_lod] = mModelLoader->mScene;
+ mVertexBuffer[loaded_lod].clear();
- setPreviewLOD(lod);
+ setPreviewLOD(loaded_lod);
- if (lod == LLModel::LOD_HIGH)
+ if (loaded_lod == LLModel::LOD_HIGH)
{ //save a copy of the highest LOD for automatic LOD manipulation
if (mBaseModel.empty())
{ //first time we've loaded a model, auto-gen LoD
mGenLOD = true;
}
- mBaseModel = mModel[lod];
+ mBaseModel = mModel[loaded_lod];
clearGLODGroup();
- mBaseScene = mScene[lod];
+ mBaseScene = mScene[loaded_lod];
mVertexBuffer[5].clear();
}
+ else
+ {
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
+ if (!legacyMatching)
+ {
+ if (!mBaseModel.empty())
+ {
+ BOOL name_based = FALSE;
+ BOOL has_submodels = FALSE;
+ for (U32 idx = 0; idx < mBaseModel.size(); ++idx)
+ {
+ if (mBaseModel[idx]->mSubmodelID)
+ { // don't do index-based renaming when the base model has submodels
+ has_submodels = TRUE;
+ if (importerDebug)
+ {
+ LL_INFOS() << "High LOD has submodels" << LL_ENDL;
+ }
+ break;
+ }
+ }
- clearIncompatible(lod);
+ for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx)
+ {
+ std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel);
+
+ LLModel* found_model = NULL;
+ LLMatrix4 transform;
+ FindModel(mBaseScene, loaded_name, found_model, transform);
+ if (found_model)
+ { // don't rename correctly named models (even if they are placed in a wrong order)
+ name_based = TRUE;
+ }
+
+ if (mModel[loaded_lod][idx]->mSubmodelID)
+ { // don't rename the models when loaded LOD model has submodels
+ has_submodels = TRUE;
+ }
+ }
+
+ if (importerDebug)
+ {
+ LL_INFOS() << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found" << LL_ENDL;
+ }
+
+ if (!name_based && !has_submodels)
+ { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601)
+ // this actually works like "ImporterLegacyMatching" for this particular LOD
+ for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx)
+ {
+ std::string name = mBaseModel[idx]->mLabel;
+ std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel);
+
+ if (loaded_name != name)
+ {
+ switch (loaded_lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (importerDebug)
+ {
+ LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL;
+ }
+
+ mModel[loaded_lod][idx]->mLabel = name;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ clearIncompatible(loaded_lod);
mDirty = true;
- if (lod == LLModel::LOD_HIGH)
+ if (loaded_lod == LLModel::LOD_HIGH)
{
resetPreviewTarget();
}
@@ -3817,6 +2096,8 @@ void LLModelPreview::loadModelCallback(S32 lod)
refresh();
mModelLoadedSignal();
+
+ mModelLoader = NULL;
}
void LLModelPreview::resetPreviewTarget()
@@ -4165,6 +2446,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
+ std::string name = base->mLabel;
+
+ switch (lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ mModel[lod][mdl_idx]->mLabel = name;
+ mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
+
GLint* sizes = new GLint[patch_count*2];
glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
stop_gloderror();
@@ -4277,17 +2572,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
{
shader->bind();
}
-
- /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty())
- { //build physics scene
- mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW];
- mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW];
-
- for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
- {
- mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]);
- }
- }*/
}
void LLModelPreview::updateStatusMessages()
@@ -4304,43 +2588,89 @@ void LLModelPreview::updateStatusMessages()
S32 total_verts[LLModel::NUM_LODS];
S32 total_submeshes[LLModel::NUM_LODS];
- for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ total_tris[i] = 0;
+ total_verts[i] = 0;
+ total_submeshes[i] = 0;
+ }
+
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
- //initialize total for this lod to 0
- total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
+ LLModelInstance& instance = *iter;
- for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter)
+ LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH];
+ if (!model_high_lod)
{
- for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
- {
- LLModel* model = instance->mModel;
- if (model)
- {
- //for each model in the lod
- S32 cur_tris = 0;
- S32 cur_verts = 0;
- S32 cur_submeshes = model->getNumVolumeFaces();
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ continue;
+ }
- for (S32 j = 0; j < cur_submeshes; ++j)
- { //for each submesh (face), add triangles and vertices to current total
- const LLVolumeFace& face = model->getVolumeFace(j);
- cur_tris += face.mNumIndices/3;
- cur_verts += face.mNumVertices;
- }
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ LLModel* lod_model = instance.mLOD[i];
+ if (!lod_model)
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+
+ if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) )
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
- //add this model to the lod total
- total_tris[lod] += cur_tris;
- total_verts[lod] += cur_verts;
- total_submeshes[lod] += cur_submeshes;
+ if (lod_model)
+ {
+ //for each model in the lod
+ S32 cur_tris = 0;
+ S32 cur_verts = 0;
+ S32 cur_submeshes = lod_model->getNumVolumeFaces();
- //store this model's counts to asset data
- tris[lod].push_back(cur_tris);
- verts[lod].push_back(cur_verts);
- submeshes[lod].push_back(cur_submeshes);
+ for (S32 j = 0; j < cur_submeshes; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = lod_model->getVolumeFace(j);
+ cur_tris += face.mNumIndices/3;
+ cur_verts += face.mNumVertices;
}
+
+ std::string instance_name = instance.mLabel;
+
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ if (importerDebug)
+ {
+ // Useful for debugging generalized complaints below about total submeshes which don't have enough
+ // context to address exactly what needs to be fixed to move towards compliance with the rules.
+ //
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL;
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL;
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL;
+
+ LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin();
+ while (mat_iter != lod_model->mMaterialList.end())
+ {
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL;
+ mat_iter++;
+ }
+ }
+
+ //add this model to the lod total
+ total_tris[i] += cur_tris;
+ total_verts[i] += cur_verts;
+ total_submeshes[i] += cur_submeshes;
+
+ //store this model's counts to asset data
+ tris[i].push_back(cur_tris);
+ verts[i].push_back(cur_verts);
+ submeshes[i].push_back(cur_submeshes);
}
}
- }
+ }
if (mMaxTriangleLimit == 0)
{
@@ -4354,37 +2684,48 @@ void LLModelPreview::updateStatusMessages()
const LLVector4a scale(0.5f);
for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
{ //for each model in the lod
- if (mModel[lod][i]->mPhysics.mHull.empty())
+ if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty())
{ //no decomp exists
S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
{ //for each submesh (face), add triangles and vertices to current total
- const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
- for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )
+ LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+ for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; )
{
- LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale);
- LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale);
- LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);
+ U16 index_a = face.mIndices[k+0];
+ U16 index_b = face.mIndices[k+1];
+ U16 index_c = face.mIndices[k+2];
+
+ LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
if (ll_is_degenerate(v1,v2,v3))
{
has_degenerate = true;
}
+ else
+ {
+ k += 3;
+ }
}
}
}
}
}
-
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
std::string mesh_status_na = mFMP->getString("mesh_status_na");
S32 upload_status[LLModel::LOD_HIGH+1];
- bool upload_ok = true;
+ mModelNoErrors = true;
- for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
+ const U32 lod_high = LLModel::LOD_HIGH;
+ U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]);
+
+ for (S32 lod = 0; lod <= lod_high; ++lod)
{
upload_status[lod] = 0;
@@ -4397,7 +2738,7 @@ void LLModelPreview::updateStatusMessages()
}
else
{
- if (lod == LLModel::LOD_HIGH)
+ if (lod == lod_high)
{
upload_status[lod] = 2;
message = "mesh_status_missing_lod";
@@ -4418,8 +2759,6 @@ void LLModelPreview::updateStatusMessages()
mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na);
}
- const U32 lod_high = LLModel::LOD_HIGH;
-
if (lod != lod_high)
{
if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
@@ -4427,6 +2766,13 @@ void LLModelPreview::updateStatusMessages()
message = "mesh_status_submesh_mismatch";
upload_status[lod] = 2;
}
+ else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count)
+ {//number of submodels is different, not all faces are matched correctly.
+ message = "mesh_status_submesh_mismatch";
+ upload_status[lod] = 2;
+ // Note: Submodels in instance were loaded from higher LOD and as result face count
+ // returns same value and total_submeshes[lod] is identical to high_lod one.
+ }
else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
{ //number of meshes is different
message = "mesh_status_mesh_mismatch";
@@ -4447,7 +2793,7 @@ void LLModelPreview::updateStatusMessages()
{
//too many vertices in this lod
message = "mesh_status_too_many_vertices";
- upload_status[lod] = 2;
+ upload_status[lod] = 1;
}
}
}
@@ -4459,7 +2805,7 @@ void LLModelPreview::updateStatusMessages()
if (upload_status[lod] >= 2)
{
- upload_ok = false;
+ mModelNoErrors = false;
}
if (lod == mPreviewLOD)
@@ -4473,23 +2819,41 @@ void LLModelPreview::updateStatusMessages()
}
- //make sure no hulls have more than 256 points in them
- for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ //warn if hulls have more than 256 points in them
+ BOOL physExceededVertexLimit = FALSE;
+ for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
{
LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i];
- for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)
+ if (mdl)
{
- if (mdl->mPhysics.mHull[j].size() > 256)
+ for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j)
{
- upload_ok = false;
+ if (mdl->mPhysics.mHull[j].size() > 256)
+ {
+ physExceededVertexLimit = TRUE;
+ LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL;
+ break;
+ }
}
}
}
+ mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
+ LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+ physStatusIcon->setVisible(physExceededVertexLimit);
+ if (physExceededVertexLimit)
+ {
+ mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
+ LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
+ physStatusIcon->setImage(img);
+ }
- bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false;
+ if (getLoadState() >= LLModelLoader::ERROR_PARSING)
+ {
+ mModelNoErrors = false;
+ LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL;
+ }
- bool skinAndRigOk = true;
bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean();
bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
@@ -4497,19 +2861,23 @@ void LLModelPreview::updateStatusMessages()
{
if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )
{
- skinAndRigOk = false;
- }
+ mModelNoErrors = false;
+ LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL;
+ }
}
-
- if(upload_ok && mModelLoader)
+
+ if(mModelNoErrors && mModelLoader)
{
if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())
{
- upload_ok = false ;
+ // Some textures are still loading, prevent upload until they are done
+ mModelNoErrors = false;
}
}
- if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate)
+ // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
+ // current use of has_degenerate won't block upload permanently - later checks will restore the button
+ if (!mModelNoErrors || has_degenerate)
{
mFMP->childDisable("ok_btn");
}
@@ -4851,7 +3219,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
LLModel* base_mdl = *base_iter;
base_iter++;
- for (S32 i = 0, e = mdl->getNumVolumeFaces(); i < e; ++i)
+ S32 num_faces = mdl->getNumVolumeFaces();
+ for (S32 i = 0; i < num_faces; ++i)
{
const LLVolumeFace &vf = mdl->getVolumeFace(i);
U32 num_vertices = vf.mNumVertices;
@@ -4946,23 +3315,23 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
void LLModelPreview::update()
{
- if (mDirty)
+ if (mGenLOD)
{
- mDirty = false;
- mResourceCost = calcResourceCost();
+ mGenLOD = false;
+ genLODs();
refresh();
updateStatusMessages();
}
- if (mGenLOD)
+ if (mDirty)
{
- mGenLOD = false;
- genLODs();
+ mDirty = false;
+ mResourceCost = calcResourceCost();
refresh();
updateStatusMessages();
}
-
}
+
//-----------------------------------------------------------------------------
// getTranslationForJointOffset()
//-----------------------------------------------------------------------------
@@ -4996,10 +3365,79 @@ void LLModelPreview::createPreviewAvatar( void )
}
else
{
- LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL;
+ LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL;
}
}
+//static
+U32 LLModelPreview::countRootModels(LLModelLoader::model_list models)
+{
+ U32 root_models = 0;
+ model_list::iterator model_iter = models.begin();
+ while (model_iter != models.end())
+ {
+ LLModel* mdl = *model_iter;
+ if (mdl && mdl->mSubmodelID == 0)
+ {
+ root_models++;
+ }
+ model_iter++;
+ }
+ return root_models;
+}
+
+void LLModelPreview::loadedCallback(
+ LLModelLoader::scene& scene,
+ LLModelLoader::model_list& model_list,
+ S32 lod,
+ void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview && !LLModelPreview::sIgnoreLoadedCallback)
+ {
+ pPreview->loadModelCallback(lod);
+ }
+}
+
+void LLModelPreview::stateChangedCallback(U32 state,void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview)
+ {
+ pPreview->setLoadState(state);
+ }
+}
+
+LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview)
+ {
+ return pPreview->getPreviewAvatar()->getJoint(str);
+ }
+ return NULL;
+}
+
+U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque)
+{
+ (void)opaque;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >;
+ LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData));
+
+ tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
+ tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE);
+ tex->forceToSaveRawImage(0, F32_MAX);
+ material.setDiffuseMap(tex->getID()); // record tex ID
+ return 1;
+ }
+
+ material.mOpaqueData = NULL;
+ return 0;
+}
+
void LLModelPreview::addEmptyFace( LLModel* pTarget )
{
U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
@@ -5253,23 +3691,9 @@ BOOL LLModelPreview::render()
if (regen)
{
genBuffers(mPreviewLOD, skin_weight);
- }
-
- //make sure material lists all match
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- if (mBaseModel.size() == mModel[i].size())
{
- for (U32 j = 0; j < mBaseModel.size(); ++j)
- {
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
-
- if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
- {
- mFMP->childDisable( "calculate_btn" );
- }
- }
+ LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL;
+ regen = TRUE;
}
}
@@ -5281,62 +3705,63 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[mPreviewLOD];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
- gGL.multMatrix((GLfloat*) mat.mMatrix);
+ gGL.multMatrix((GLfloat*) mat.mMatrix);
- for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i)
- {
- LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
-
- buffer->setBuffer(type_mask & buffer->getTypeMask());
- if (textures)
+ U32 num_models = mVertexBuffer[mPreviewLOD][model].size();
+ for (U32 i = 0; i < num_models; ++i)
{
- int materialCnt = instance.mModel->mMaterialList.size();
- if ( i < materialCnt )
+ LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
+
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+
+ if (textures)
{
- const std::string& binding = instance.mModel->mMaterialList[i];
- const LLImportMaterial& material = instance.mMaterial[binding];
+ int materialCnt = instance.mModel->mMaterialList.size();
+ if ( i < materialCnt )
+ {
+ const std::string& binding = instance.mModel->mMaterialList[i];
+ const LLImportMaterial& material = instance.mMaterial[binding];
- gGL.diffuseColor4fv(material.mDiffuseColor.mV);
+ gGL.diffuseColor4fv(material.mDiffuseColor.mV);
- if (material.mDiffuseMap.notNull())
- {
- if (material.mDiffuseMap->getDiscardLevel() > -1)
+ // Find the tex for this material, bind it, and add it to our set
+ //
+ LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
+ if (tex)
{
- gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
- mTextureSet.insert(material.mDiffuseMap.get());
+ mTextureSet.insert(tex);
}
}
}
- }
- else
- {
- gGL.diffuseColor4f(1,1,1,1);
- }
-
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+ else
+ {
+ gGL.diffuseColor4f(1,1,1,1);
+ }
- if (edges)
- {
- glLineWidth(3.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+
+ if (edges)
+ {
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
}
+ gGL.popMatrix();
}
- gGL.popMatrix();
- }
if (physics)
{
@@ -5364,97 +3789,99 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
gGL.multMatrix((GLfloat*) mat.mMatrix);
- bool render_mesh = true;
+ bool render_mesh = true;
- LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
- if (decomp)
- {
- LLMutexLock(decomp->mMutex);
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
+ {
+ LLMutexLock(decomp->mMutex);
- LLModel::Decomposition& physics = model->mPhysics;
+ LLModel::Decomposition& physics = model->mPhysics;
- if (!physics.mHull.empty())
- {
- render_mesh = false;
+ if (!physics.mHull.empty())
+ {
+ render_mesh = false;
- if (physics.mMesh.empty())
- { //build vertex buffer for physics mesh
- gMeshRepo.buildPhysicsMesh(physics);
- }
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
- if (!physics.mMesh.empty())
- { //render hull instead of mesh
- for (U32 i = 0; i < physics.mMesh.size(); ++i)
- {
- if (explode > 0.f)
+ if (!physics.mMesh.empty())
+ { //render hull instead of mesh
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
{
- gGL.pushMatrix();
+ if (explode > 0.f)
+ {
+ gGL.pushMatrix();
- LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
- offset *= explode;
+ LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
+ offset *= explode;
- gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
- }
+ gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+ }
- static std::vector<LLColor4U> hull_colors;
+ static std::vector<LLColor4U> hull_colors;
- if (i+1 >= hull_colors.size())
- {
- hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
- }
+ if (i+1 >= hull_colors.size())
+ {
+ hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
+ }
- gGL.diffuseColor4ubv(hull_colors[i].mV);
- LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+ gGL.diffuseColor4ubv(hull_colors[i].mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
- if (explode > 0.f)
- {
- gGL.popMatrix();
+ if (explode > 0.f)
+ {
+ gGL.popMatrix();
+ }
}
}
}
}
- }
-
- if (render_mesh)
- {
- if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
- {
- genBuffers(LLModel::LOD_PHYSICS, false);
- }
- for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
+
+ if (render_mesh)
{
- LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+ {
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
+
+ U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+ for (U32 i = 0; i < num_models; ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
- buffer->setBuffer(type_mask & buffer->getTypeMask());
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.diffuseColor3f(1.f, 1.f, 0.f);
+ gGL.diffuseColor3f(1.f, 1.f, 0.f);
- glLineWidth(2.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glLineWidth(2.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
}
- }
- gGL.popMatrix();
- }
+ gGL.popMatrix();
+ }
glLineWidth(3.f);
glPointSize(8.f);
@@ -5635,20 +4062,20 @@ BOOL LLModelPreview::render()
position[j] = v;
}
- llassert(model->mMaterialList.size() > i);
+ llassert(model->mMaterialList.size() > i);
const std::string& binding = instance.mModel->mMaterialList[i];
const LLImportMaterial& material = instance.mMaterial[binding];
buffer->setBuffer(type_mask & buffer->getTypeMask());
gGL.diffuseColor4fv(material.mDiffuseColor.mV);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- if (material.mDiffuseMap.notNull())
+
+ // Find the tex for this material, bind it, and add it to our set
+ //
+ LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
+ if (tex)
{
- if (material.mDiffuseMap->getDiscardLevel() > -1)
- {
- gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
- mTextureSet.insert(material.mDiffuseMap.get());
- }
+ mTextureSet.insert(tex);
}
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
@@ -5763,14 +4190,14 @@ void LLFloaterModelPreview::onReset(void* user_data)
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
fmp->childDisable("reset_btn");
LLModelPreview* mp = fmp->mModelPreview;
- std::string filename = mp->mLODFile[3];
+ std::string filename = mp->mLODFile[LLModel::LOD_HIGH];
fmp->resetDisplayOptions();
//reset model preview
fmp->initModelPreview();
mp = fmp->mModelPreview;
- mp->loadModel(filename,3,true);
+ mp->loadModel(filename,LLModel::LOD_HIGH,true);
}
//static
@@ -5864,7 +4291,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
}
mUploadBtn->setVisible(!visible);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ mUploadBtn->setEnabled(isModelUploadAllowed());
if (visible)
{
@@ -5930,7 +4357,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
childSetVisible("upload_fee", true);
childSetVisible("price_breakdown", true);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ mUploadBtn->setEnabled(isModelUploadAllowed());
}
void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)
@@ -5954,6 +4381,16 @@ void LLFloaterModelPreview::onModelUploadFailure()
mUploadBtn->setEnabled(true);
}
+bool LLFloaterModelPreview::isModelUploadAllowed()
+{
+ bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty();
+ if (mModelPreview)
+ {
+ allow_upload &= mModelPreview->mModelNoErrors;
+ }
+ return allow_upload;
+}
+
S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
{
if (mContinue)
@@ -6012,8 +4449,8 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
LL_WARNS() << "Upload permission set to true but uploadModelUrl is empty!" << LL_ENDL;
}
- //mUploadBtn->setEnabled(mHasUploadPerm);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ // isModelUploadAllowed() includes mHasUploadPerm
+ mUploadBtn->setEnabled(isModelUploadAllowed());
getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);
getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);
}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 618748bd4e..7a518c798b 100755
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -37,6 +37,8 @@
#include "llviewermenufile.h"
#include "llfloatermodeluploadbase.h"
+#include "lldaeloader.h"
+
class LLComboBox;
class LLJoint;
class LLViewerJointMesh;
@@ -45,103 +47,18 @@ class LLTextBox;
class LLVertexBuffer;
class LLModelPreview;
class LLFloaterModelPreview;
+class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
+class domSkin;
+class domMesh;
class LLMenuButton;
class LLToggleableMenu;
-typedef std::map<std::string, LLMatrix4> JointTransformMap;
-typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
-
-const S32 NUM_LOD = 4;
-
-class LLModelLoader : public LLThread
-{
-public:
- typedef enum
- {
- STARTING = 0,
- READING_FILE,
- CREATING_FACES,
- GENERATING_VERTEX_BUFFERS,
- GENERATING_LOD,
- DONE,
- ERROR_PARSING, //basically loading failed
- ERROR_MATERIALS,
- } eLoadState;
-
- U32 mState;
- std::string mFilename;
- S32 mLod;
- LLModelPreview* mPreview;
- LLMatrix4 mTransform;
- BOOL mFirstTransform;
- LLVector3 mExtents[2];
- bool mTrySLM;
-
- std::map<daeElement*, LLPointer<LLModel> > mModel;
-
- typedef std::vector<LLPointer<LLModel> > model_list;
- model_list mModelList;
-
- typedef std::vector<LLModelInstance> model_instance_list;
-
- typedef std::map<LLMatrix4, model_instance_list > scene;
-
- scene mScene;
-
- typedef std::queue<LLPointer<LLModel> > model_queue;
-
- //queue of models that need a physics rep
- model_queue mPhysicsQ;
-
- LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
- std::deque<std::string>& jointsFromNodes );
- ~LLModelLoader() ;
-
- virtual void run();
- bool doLoadModel();
- bool loadFromSLM(const std::string& filename);
- void loadModelCallback();
-
- void loadTextures() ; //called in the main thread.
- void processElement(daeElement* element, bool& badElement);
- std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
- LLImportMaterial profileToMaterial(domProfile_COMMON* material);
- std::string getElementLabel(daeElement *element);
- LLColor4 getDaeColor(daeElement* element);
-
- daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
-
- bool isNodeAJoint( domNode* pNode );
- void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
- void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
- void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
- void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
-
- void setLoadState(U32 state);
-
- void buildJointToNodeMappingFromScene( daeElement* pRoot );
- void processJointToNodeMapping( domNode* pNode );
- void processChildJoints( domNode* pParentNode );
-
- //map of avatar joints as named in COLLADA assets to internal joint names
- std::map<std::string, std::string> mJointMap;
- JointTransformMap& mJointList;
- std::deque<std::string>& mJointsFromNode;
-
- S32 mNumOfFetchingTextures ; //updated in the main thread
- bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
-
-private:
- static std::list<LLModelLoader*> sActiveLoaderList;
- static bool isAlive(LLModelLoader* loader) ;
-};
-
class LLFloaterModelPreview : public LLFloaterModelUploadBase
{
public:
@@ -172,6 +89,7 @@ public:
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ void onOpen(const LLSD& key);
+ /*virtual*/ void onClose(bool app_quitting);
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
@@ -210,6 +128,8 @@ public:
/*virtual*/ void onModelUploadFailure();
+ bool isModelUploadAllowed();
+
protected:
friend class LLModelPreview;
friend class LLMeshFilePicker;
@@ -359,21 +279,14 @@ public:
void setHasPivot( bool val ) { mHasPivot = val; }
void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
- //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
- void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
- void critiqueJointToNodeMappingFromScene( void );
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
//Accessors for joint position upload friendly rigs
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
- bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
- //Determines if a rig is a legacy from the joint list
- bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
+
//Accessors for the legacy rigs
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
- void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
- //Verify that a controller matches vertex counts
- bool verifyController( domController* pController );
+ void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
@@ -388,6 +301,16 @@ public:
LLVector3 getTranslationForJointOffset( std::string joint );
+ static bool sIgnoreLoadedCallback;
+
+protected:
+
+ static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque);
+ static void stateChangedCallback(U32 state, void* opaque);
+
+ static LLJoint* lookupJointByName(const std::string&, void* opaque);
+ static U32 loadTextures(LLImportMaterial& material, void* opaque);
+
private:
//Utility function for controller vertex compare
bool verifyCount( int expected, int result );
@@ -395,6 +318,8 @@ private:
void createPreviewAvatar( void );
//Accessor for the dummy avatar
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
+ // Count amount of original models, excluding sub-models
+ static U32 countRootModels(LLModelLoader::model_list models);
protected:
friend class LLModelLoader;
@@ -416,13 +341,15 @@ private:
LLVector3 mPreviewTarget;
LLVector3 mPreviewScale;
S32 mPreviewLOD;
+ S32 mPhysicsSearchLOD;
U32 mResourceCost;
std::string mLODFile[LLModel::NUM_LODS];
bool mLoading;
U32 mLoadState;
bool mResetJoints;
bool mRigParityWithScene;
-
+ bool mModelNoErrors;
+
std::map<std::string, bool> mViewOption;
//GLOD object parameters (must rebuild object if these change)
@@ -459,7 +386,7 @@ private:
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
- std::set<LLViewerFetchedTexture* > mTextureSet;
+ std::set<LLViewerFetchedTexture * > mTextureSet;
//map of vertex buffers to models (one vertex buffer in vector per face in model
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
@@ -478,10 +405,9 @@ private:
bool mLastJointUpdate;
- std::deque<std::string> mMasterJointList;
- std::deque<std::string> mMasterLegacyJointList;
- std::deque<std::string> mJointsFromNode;
- JointTransformMap mJointTransformMap;
+ JointSet mJointsFromNode;
+ JointTransformMap mJointTransformMap;
+
LLPointer<LLVOAvatar> mPreviewAvatar;
};
diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp
index e2f84fd990..0fe97fd610 100755
--- a/indra/newview/llfloatermodeluploadbase.cpp
+++ b/indra/newview/llfloatermodeluploadbase.cpp
@@ -70,7 +70,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro(std::string url
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp
new file mode 100644
index 0000000000..4b5fe4989a
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.cpp
@@ -0,0 +1,575 @@
+/**
+ * @file llfloaternotificationstabbed.cpp
+ * @brief
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h" // must be first include
+#include "llfloaternotificationstabbed.h"
+
+#include "llchiclet.h"
+#include "llchicletbar.h"
+#include "llflatlistview.h"
+#include "llfloaterreg.h"
+#include "llnotificationmanager.h"
+#include "llnotificationsutil.h"
+#include "llscriptfloater.h"
+#include "llspeakers.h"
+#include "lltoastpanel.h"
+#include "lltoastnotifypanel.h"
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::LLFloaterNotificationsTabbed(const LLSD& key) : LLTransientDockableFloater(NULL, true, key),
+ mChannel(NULL),
+ mSysWellChiclet(NULL),
+ mGroupInviteMessageList(NULL),
+ mGroupNoticeMessageList(NULL),
+ mTransactionMessageList(NULL),
+ mSystemMessageList(NULL),
+ mNotificationsSeparator(NULL),
+ mNotificationsTabContainer(NULL),
+ NOTIFICATION_TABBED_ANCHOR_NAME("notification_well_panel"),
+ IM_WELL_ANCHOR_NAME("im_well_panel"),
+ mIsReshapedByUser(false)
+
+{
+ setOverlapsScreenChannel(true);
+ mNotificationUpdates.reset(new NotificationTabbedChannel(this));
+ mNotificationsSeparator = new LLNotificationSeparator();
+}
+
+//---------------------------------------------------------------------------------
+BOOL LLFloaterNotificationsTabbed::postBuild()
+{
+ mGroupInviteMessageList = getChild<LLNotificationListView>("group_invite_notification_list");
+ mGroupNoticeMessageList = getChild<LLNotificationListView>("group_notice_notification_list");
+ mTransactionMessageList = getChild<LLNotificationListView>("transaction_notification_list");
+ mSystemMessageList = getChild<LLNotificationListView>("system_notification_list");
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupInviteTypes(), mGroupInviteMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupNoticeTypes(), mGroupNoticeMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getTransactionTypes(), mTransactionMessageList);
+ mNotificationsSeparator->initUnTaggedList(mSystemMessageList);
+ mNotificationsTabContainer = getChild<LLTabContainer>("notifications_tab_container");
+
+ mDeleteAllBtn = getChild<LLButton>("delete_all_button");
+ mDeleteAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickDeleteAllBtn,this));
+
+ mCollapseAllBtn = getChild<LLButton>("collapse_all_button");
+ mCollapseAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickCollapseAllBtn,this));
+
+ // get a corresponding channel
+ initChannel();
+ BOOL rv = LLTransientDockableFloater::postBuild();
+
+ setTitle(getString("title_notification_tabbed_window"));
+ return rv;
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setMinimized(BOOL minimize)
+{
+ LLTransientDockableFloater::setMinimized(minimize);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::handleReshape(const LLRect& rect, bool by_user)
+{
+ mIsReshapedByUser |= by_user; // mark floater that it is reshaped by user
+ LLTransientDockableFloater::handleReshape(rect, by_user);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onStartUpToastClick(S32 x, S32 y, MASK mask)
+{
+ // just set floater visible. Screen channels will be cleared.
+ setVisible(TRUE);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setSysWellChiclet(LLSysWellChiclet* chiclet)
+{
+ mSysWellChiclet = chiclet;
+ if(NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::~LLFloaterNotificationsTabbed()
+{
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::removeItemByID(const LLUUID& id, std::string type)
+{
+ if(mNotificationsSeparator->removeItemByID(type, id))
+ {
+ if (NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+ reshapeWindow();
+ updateNotificationCounters();
+ }
+ else
+ {
+ LL_WARNS() << "Unable to remove notification from the list, ID: " << id
+ << LL_ENDL;
+ }
+
+ // hide chiclet window if there are no items left
+ if(isWindowEmpty())
+ {
+ setVisible(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::string type)
+{
+ return mNotificationsSeparator->findItemByID(type, id);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::initChannel()
+{
+ LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
+ LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
+ if(NULL == mChannel)
+ {
+ LL_WARNS() << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << LL_ENDL;
+ }
+
+ if(mChannel)
+ {
+ mChannel->addOnStoreToastCallback(boost::bind(&LLFloaterNotificationsTabbed::onStoreToast, this, _1, _2));
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setVisible(BOOL visible)
+{
+ if (visible)
+ {
+ // when Notification channel is cleared, storable toasts will be added into the list.
+ clearScreenChannels();
+ }
+ if (visible)
+ {
+ if (NULL == getDockControl() && getDockTongue().notNull())
+ {
+ setDockControl(new LLDockControl(
+ LLChicletBar::getInstance()->getChild<LLView>(getAnchorViewName()), this,
+ getDockTongue(), LLDockControl::BOTTOM));
+ }
+ }
+
+ // do not show empty window
+ if (NULL == mNotificationsSeparator || isWindowEmpty()) visible = FALSE;
+
+ LLTransientDockableFloater::setVisible(visible);
+
+ // update notification channel state
+ initChannel(); // make sure the channel still exists
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setDocked(bool docked, bool pop_on_undock)
+{
+ LLTransientDockableFloater::setDocked(docked, pop_on_undock);
+
+ // update notification channel state
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::reshapeWindow()
+{
+ // update notification channel state
+ // update on a window reshape is important only when a window is visible and docked
+ if(mChannel && getVisible() && isDocked())
+ {
+ mChannel->updateShowToastsState();
+ }
+}
+
+//---------------------------------------------------------------------------------
+bool LLFloaterNotificationsTabbed::isWindowEmpty()
+{
+ return mNotificationsSeparator->size() == 0;
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::NotificationTabbedChannel::NotificationTabbedChannel(LLFloaterNotificationsTabbed* notifications_tabbed_window)
+ : LLNotificationChannel(LLNotificationChannel::Params().name(notifications_tabbed_window->getPathname())),
+ mNotificationsTabbedWindow(notifications_tabbed_window)
+{
+ connectToChannel("Notifications");
+ connectToChannel("Group Notifications");
+ connectToChannel("Offer");
+}
+
+// static
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed* LLFloaterNotificationsTabbed::getInstance(const LLSD& key /*= LLSD()*/)
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterNotificationsTabbed>("notification_well_window", key);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[COUNT]"] = llformat("%d", counterValue);
+ std::string label = getString(stringName, string_args);
+ mNotificationsTabContainer->setPanelTitle(panelIndex, label);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounters()
+{
+ updateNotificationCounter(0, mSystemMessageList->size(), "system_tab_title");
+ updateNotificationCounter(1, mTransactionMessageList->size(), "transactions_tab_title");
+ updateNotificationCounter(2, mGroupInviteMessageList->size(), "group_invitations_tab_title");
+ updateNotificationCounter(3, mGroupNoticeMessageList->size(), "group_notices_tab_title");
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::addItem(LLNotificationListItem::Params p)
+{
+ // do not add clones
+ if (mNotificationsSeparator->findItemByID(p.notification_name, p.notification_id))
+ return;
+ LLNotificationListItem* new_item = LLNotificationListItem::create(p);
+ if (new_item == NULL)
+ {
+ return;
+ }
+ if (mNotificationsSeparator->addItem(new_item->getNotificationName(), new_item))
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ reshapeWindow();
+ updateNotificationCounters();
+ new_item->setOnItemCloseCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClose, this, _1));
+ new_item->setOnItemClickCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClick, this, _1));
+ }
+ else
+ {
+ LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
+ << ", title: " << new_item->getTitle()
+ << LL_ENDL;
+
+ new_item->die();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAll()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+
+ std::vector<LLNotificationListItem*> items;
+ mNotificationsSeparator->getItems(items);
+ std::vector<LLNotificationListItem*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ onItemClose(*iter);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const
+{
+ switch (mNotificationsTabContainer->getCurrentPanelIndex())
+ {
+ case 0:
+ mSystemMessageList->getItems(items);
+ break;
+ case 1:
+ mTransactionMessageList->getItems(items);
+ break;
+ case 2:
+ mGroupInviteMessageList->getItems(items);
+ break;
+ case 3:
+ mGroupNoticeMessageList->getItems(items);
+ break;
+ default:
+ break;
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAllOnCurrentTab()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ onItemClose(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::collapseAllOnCurrentTab()
+{
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ notify_item->setExpanded(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::clearScreenChannels()
+{
+ // 1 - remove StartUp toast and channel if present
+ if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
+ {
+ LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
+ }
+
+ // 2 - remove toasts in Notification channel
+ if(mChannel)
+ {
+ mChannel->removeAndStoreAllStorableToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onStoreToast(LLPanel* info_panel, LLUUID id)
+{
+ LLNotificationListItem::Params p;
+ p.notification_id = id;
+ p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
+ LLNotificationPtr notify = mChannel->getToastByNotificationID(id)->getNotification();
+ LLSD payload = notify->getPayload();
+ p.notification_name = notify->getName();
+ p.transaction_id = payload["transaction_id"];
+ p.group_id = payload["group_id"];
+ p.fee = payload["fee"];
+ p.subject = payload["subject"].asString();
+ p.message = payload["message"].asString();
+ p.sender = payload["sender_name"].asString();
+ p.time_stamp = notify->getDate();
+ p.received_time = payload["received_time"].asDate();
+ p.paid_from_id = payload["from_id"];
+ p.paid_to_id = payload["dest_id"];
+ p.inventory_offer = payload["inventory_offer"];
+ p.notification_priority = notify->getPriority();
+ addItem(p);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClick(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+ if (item->showPopup())
+ {
+ LLFloaterReg::showInstance("inspect_toast", id);
+ }
+ else
+ {
+ item->setExpanded(TRUE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClose(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+
+ if(mChannel)
+ {
+ // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
+ mChannel->killToastByNotificationID(id);
+ }
+ else
+ {
+ // removeItemByID() should be called one time for each item to remove it from notification well
+ removeItemByID(id, item->getNotificationName());
+ }
+
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onAdd( LLNotificationPtr notify )
+{
+ removeItemByID(notify->getID(), notify->getName());
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickDeleteAllBtn()
+{
+ closeAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickCollapseAllBtn()
+{
+ collapseAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::string& tag, LLNotificationListView* list)
+{
+ mNotificationListMap.insert(notification_list_map_t::value_type(tag, list));
+ mNotificationLists.push_back(list);
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list)
+{
+ std::set<std::string>::const_iterator it = tags.begin();
+ for(;it != tags.end();it++)
+ {
+ initTaggedList(*it, list);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initUnTaggedList(LLNotificationListView* list)
+{
+ mUnTaggedList = list;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::addItem(std::string& tag, LLNotificationListItem* item)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->addNotification(item);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->addNotification(item);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::removeItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->removeItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->removeItemByValue(id);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+U32 LLNotificationSeparator::size() const
+{
+ U32 size = 0;
+ notification_list_list_t::const_iterator it = mNotificationLists.begin();
+ for (; it != mNotificationLists.end(); it++)
+ {
+ size = size + (*it)->size();
+ }
+ if (mUnTaggedList != NULL)
+ {
+ size = size + mUnTaggedList->size();
+ }
+ return size;
+}
+
+//---------------------------------------------------------------------------------
+LLPanel* LLNotificationSeparator::findItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->getItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->getItemByValue(id);
+ }
+
+ return NULL;
+}
+
+//static
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list)
+{
+ std::vector<LLPanel*> list_items;
+ list->getItems(list_items);
+ std::vector<LLPanel*>::iterator it = list_items.begin();
+ for (; it != list_items.end(); ++it)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*it);
+ if (notify_item)
+ items.push_back(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItems(std::vector<LLNotificationListItem*>& items) const
+{
+ items.clear();
+ notification_list_list_t::const_iterator lists_it = mNotificationLists.begin();
+ for (; lists_it != mNotificationLists.end(); lists_it++)
+ {
+ getItemsFromList(items, *lists_it);
+ }
+ if (mUnTaggedList != NULL)
+ {
+ getItemsFromList(items, mUnTaggedList);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::LLNotificationSeparator()
+ : mUnTaggedList(NULL)
+{}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::~LLNotificationSeparator()
+{}
diff --git a/indra/newview/llfloaternotificationstabbed.h b/indra/newview/llfloaternotificationstabbed.h
new file mode 100644
index 0000000000..8dd20b18c4
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.h
@@ -0,0 +1,174 @@
+/**
+ * @file llfloaternotificationstabbed.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_FLOATERNOTIFICATIONSTABBED_H
+#define LL_FLOATERNOTIFICATIONSTABBED_H
+
+#include "llimview.h"
+#include "llnotifications.h"
+#include "llscreenchannel.h"
+#include "llsyswellitem.h"
+#include "lltransientdockablefloater.h"
+#include "llnotificationlistview.h"
+#include "lltabcontainer.h"
+
+class LLAvatarName;
+class LLChiclet;
+class LLFlatListView;
+class LLIMChiclet;
+class LLScriptChiclet;
+class LLSysWellChiclet;
+
+class LLNotificationSeparator
+{
+public:
+ LLNotificationSeparator();
+ ~LLNotificationSeparator();
+ void initTaggedList(const std::string& tag, LLNotificationListView* list);
+ void initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list);
+ void initUnTaggedList(LLNotificationListView* list);
+ bool addItem(std::string& tag, LLNotificationListItem* item);
+ LLPanel* findItemByID(std::string& tag, const LLUUID& id);
+ bool removeItemByID(std::string& tag, const LLUUID& id);
+ void getItems(std::vector<LLNotificationListItem*>& items) const;
+ U32 size() const;
+private:
+ static void getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list);
+
+ typedef std::map<std::string, LLNotificationListView*> notification_list_map_t;
+ notification_list_map_t mNotificationListMap;
+ typedef std::list<LLNotificationListView*> notification_list_list_t;
+ notification_list_list_t mNotificationLists;
+ LLNotificationListView* mUnTaggedList;
+};
+
+class LLFloaterNotificationsTabbed : public LLTransientDockableFloater
+{
+public:
+ LOG_CLASS(LLFloaterNotificationsTabbed);
+
+ LLFloaterNotificationsTabbed(const LLSD& key);
+ virtual ~LLFloaterNotificationsTabbed();
+ BOOL postBuild();
+
+ // other interface functions
+ // check is window empty
+ bool isWindowEmpty();
+
+ // Operating with items
+ void removeItemByID(const LLUUID& id, std::string type);
+ LLPanel * findItemByID(const LLUUID& id, std::string type);
+ void updateNotificationCounters();
+ void updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName);
+
+ // Operating with outfit
+ virtual void setVisible(BOOL visible);
+
+ /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
+ // override LLFloater's minimization according to EXT-1216
+ /*virtual*/ void setMinimized(BOOL minimize);
+ /*virtual*/ void handleReshape(const LLRect& rect, bool by_user);
+
+ void onStartUpToastClick(S32 x, S32 y, MASK mask);
+ /*virtual*/ void onAdd(LLNotificationPtr notify);
+
+ void setSysWellChiclet(LLSysWellChiclet* chiclet);
+ void closeAll();
+
+ static LLFloaterNotificationsTabbed* getInstance(const LLSD& key = LLSD());
+
+ // size constants for the window and for its elements
+ static const S32 MAX_WINDOW_HEIGHT = 200;
+ static const S32 MIN_WINDOW_WIDTH = 318;
+
+private:
+ // init Window's channel
+ virtual void initChannel();
+
+ const std::string NOTIFICATION_TABBED_ANCHOR_NAME;
+ const std::string IM_WELL_ANCHOR_NAME;
+ //virtual const std::string& getAnchorViewName() = 0;
+
+ void reshapeWindow();
+
+ // pointer to a corresponding channel's instance
+ LLNotificationsUI::LLScreenChannel* mChannel;
+
+ /**
+ * Reference to an appropriate Well chiclet to release "new message" state. EXT-3147
+ */
+ LLSysWellChiclet* mSysWellChiclet;
+
+ bool mIsReshapedByUser;
+
+ struct NotificationTabbedChannel : public LLNotificationChannel
+ {
+ NotificationTabbedChannel(LLFloaterNotificationsTabbed*);
+ void onDelete(LLNotificationPtr notify)
+ {
+ mNotificationsTabbedWindow->removeItemByID(notify->getID(), notify->getName());
+ }
+
+ LLFloaterNotificationsTabbed* mNotificationsTabbedWindow;
+ };
+
+ LLNotificationChannelPtr mNotificationUpdates;
+ virtual const std::string& getAnchorViewName() { return NOTIFICATION_TABBED_ANCHOR_NAME; }
+
+ // init Window's channel
+ // void initChannel();
+ void clearScreenChannels();
+ // Operating with items
+ void addItem(LLNotificationListItem::Params p);
+ void getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const;
+
+ // Closes all notifications and removes them from the Notification Well
+ void closeAllOnCurrentTab();
+ void collapseAllOnCurrentTab();
+
+ void onStoreToast(LLPanel* info_panel, LLUUID id);
+ void onClickDeleteAllBtn();
+ void onClickCollapseAllBtn();
+ // Handlers
+ void onItemClick(LLNotificationListItem* item);
+ void onItemClose(LLNotificationListItem* item);
+ // ID of a toast loaded by user (by clicking notification well item)
+ LLUUID mLoadedToastId;
+
+ LLNotificationListView* mGroupInviteMessageList;
+ LLNotificationListView* mGroupNoticeMessageList;
+ LLNotificationListView* mTransactionMessageList;
+ LLNotificationListView* mSystemMessageList;
+ LLNotificationSeparator* mNotificationsSeparator;
+ LLTabContainer* mNotificationsTabContainer;
+ LLButton* mDeleteAllBtn;
+ LLButton* mCollapseAllBtn;
+};
+
+#endif // LL_FLOATERNOTIFICATIONSTABBED_H
+
+
+
diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp
deleted file mode 100755
index b7b1634a5f..0000000000
--- a/indra/newview/llfloateroutbox.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-/**
- * @file llfloateroutbox.cpp
- * @brief Implementation of the merchant outbox window
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloateroutbox.h"
-
-#include "llfloaterreg.h"
-#include "llfolderview.h"
-#include "llinventorybridge.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llinventoryobserver.h"
-#include "llinventorypanel.h"
-#include "llmarketplacefunctions.h"
-#include "llnotificationhandler.h"
-#include "llnotificationmanager.h"
-#include "llnotificationsutil.h"
-#include "lltextbox.h"
-#include "lltransientfloatermgr.h"
-#include "lltrans.h"
-#include "llviewernetwork.h"
-#include "llwindowshade.h"
-
-
-///----------------------------------------------------------------------------
-/// LLOutboxNotification class
-///----------------------------------------------------------------------------
-
-LLNotificationsUI::LLOutboxNotification::LLOutboxNotification()
- : LLSystemNotificationHandler("Outbox", "outbox")
-{
-}
-
-bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLNotificationPtr& notify)
-{
- LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox");
-
- outbox_floater->showNotification(notify);
-
- return false;
-}
-
-void LLNotificationsUI::LLOutboxNotification::onDelete(LLNotificationPtr p)
-{
- LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- if (notification_handler)
- {
- notification_handler->onDelete(p);
- }
-}
-
-///----------------------------------------------------------------------------
-/// LLOutboxAddedObserver helper class
-///----------------------------------------------------------------------------
-
-class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver
-{
-public:
- LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater)
- : LLInventoryCategoryAddedObserver()
- , mOutboxFloater(outboxFloater)
- {
- }
-
- void done()
- {
- for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it)
- {
- LLViewerInventoryCategory* added_category = *it;
-
- LLFolderType::EType added_category_type = added_category->getPreferredType();
-
- if (added_category_type == LLFolderType::FT_OUTBOX)
- {
- mOutboxFloater->initializeMarketPlace();
- }
- }
- }
-
-private:
- LLFloaterOutbox * mOutboxFloater;
-};
-
-///----------------------------------------------------------------------------
-/// LLFloaterOutbox
-///----------------------------------------------------------------------------
-
-LLFloaterOutbox::LLFloaterOutbox(const LLSD& key)
- : LLFloater(key)
- , mCategoriesObserver(NULL)
- , mCategoryAddedObserver(NULL)
- , mImportBusy(false)
- , mImportButton(NULL)
- , mInventoryFolderCountText(NULL)
- , mInventoryImportInProgress(NULL)
- , mInventoryPlaceholder(NULL)
- , mInventoryText(NULL)
- , mInventoryTitle(NULL)
- , mOutboxId(LLUUID::null)
- , mOutboxItemCount(0)
- , mOutboxTopLevelDropZone(NULL)
- , mWindowShade(NULL)
-{
-}
-
-LLFloaterOutbox::~LLFloaterOutbox()
-{
- if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- }
- delete mCategoriesObserver;
-
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- }
- delete mCategoryAddedObserver;
-}
-
-BOOL LLFloaterOutbox::postBuild()
-{
- mInventoryFolderCountText = getChild<LLTextBox>("outbox_folder_count");
- mInventoryImportInProgress = getChild<LLView>("import_progress_indicator");
- mInventoryPlaceholder = getChild<LLView>("outbox_inventory_placeholder_panel");
- mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_text");
- mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_title");
-
- mImportButton = getChild<LLButton>("outbox_import_btn");
- mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this));
-
- mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target");
-
- LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this));
-
- // Observe category creation to catch outbox creation (moot if already existing)
- mCategoryAddedObserver = new LLOutboxAddedObserver(this);
- gInventory.addObserver(mCategoryAddedObserver);
-
- // Setup callbacks for importer
- LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance();
- importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2));
- importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1));
- importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2));
-
- return TRUE;
-}
-
-void LLFloaterOutbox::cleanOutbox()
-{
- // Note: we cannot delete the mOutboxInventoryPanel as that point
- // as this is called through callback observers of the panel itself.
- // Doing so would crash rapidly.
-
- // Invalidate the outbox data
- mOutboxId.setNull();
- mOutboxItemCount = 0;
-}
-
-void LLFloaterOutbox::onClose(bool app_quitting)
-{
- if (mWindowShade)
- {
- delete mWindowShade;
-
- mWindowShade = NULL;
- }
-}
-
-void LLFloaterOutbox::onOpen(const LLSD& key)
-{
- //
- // Initialize the Market Place or go update the outbox
- //
- if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
- {
- initializeMarketPlace();
- }
- else
- {
- setupOutbox();
- }
-
- //
- // Update the floater view
- //
- updateView();
-
- //
- // Trigger fetch of outbox contents
- //
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::onFocusReceived()
-{
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::fetchOutboxContents()
-{
- if (mOutboxId.notNull())
- {
- LLInventoryModelBackgroundFetch::instance().start(mOutboxId);
- }
-}
-
-void LLFloaterOutbox::setupOutbox()
-{
- if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)
- {
- // If we are *not* a merchant or we have no market place connection established yet, do nothing
- return;
- }
-
- // We are a merchant. Get the outbox, create it if needs be.
- LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true);
- if (outbox_id.isNull())
- {
- // We should never get there unless the inventory fails badly
- LL_ERRS() << "Inventory problem: failure to create the outbox for a merchant!" << LL_ENDL;
- return;
- }
-
- // Consolidate Merchant Outbox
- // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, things get messy and conventions get broken down eventually
- gInventory.consolidateForType(outbox_id, LLFolderType::FT_OUTBOX);
-
- if (outbox_id == mOutboxId)
- {
- LL_WARNS() << "Inventory warning: Merchant outbox already set" << LL_ENDL;
- return;
- }
- mOutboxId = outbox_id;
-
- // No longer need to observe new category creation
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- delete mCategoryAddedObserver;
- mCategoryAddedObserver = NULL;
- }
- llassert(!mCategoryAddedObserver);
-
- // Create observer for outbox modifications : clear the old one and create a new one
- if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- delete mCategoriesObserver;
- }
- mCategoriesObserver = new LLInventoryCategoriesObserver();
- gInventory.addObserver(mCategoriesObserver);
- mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this));
- llassert(mCategoriesObserver);
-
- // Set up the outbox inventory view
- LLInventoryPanel* inventory_panel = mOutboxInventoryPanel.get();
- if (inventory_panel)
- {
- delete inventory_panel;
- }
- inventory_panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_outbox_inventory.xml", mInventoryPlaceholder->getParent(), LLInventoryPanel::child_registry_t::instance());
- mOutboxInventoryPanel = inventory_panel->getInventoryPanelHandle();
- llassert(mOutboxInventoryPanel.get() != NULL);
-
- // Reshape the inventory to the proper size
- LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect();
- inventory_panel->setShape(inventory_placeholder_rect);
-
- // Set the sort order newest to oldest
- inventory_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
- inventory_panel->getFilter().markDefault();
-
- // Get the content of the outbox
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::initializeMarketPlace()
-{
- //
- // Initialize the marketplace import API
- //
- LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance();
- if (!importer.isInitialized())
- {
- importer.initialize();
- }
-}
-
-void LLFloaterOutbox::setStatusString(const std::string& statusString)
-{
- llassert(mInventoryFolderCountText != NULL);
-
- mInventoryFolderCountText->setText(statusString);
-}
-
-void LLFloaterOutbox::updateFolderCount()
-{
- if (mOutboxInventoryPanel.get() && mOutboxId.notNull())
- {
- U32 item_count = 0;
-
- if (mOutboxId.notNull())
- {
- LLInventoryModel::cat_array_t * cats;
- LLInventoryModel::item_array_t * items;
- gInventory.getDirectDescendentsOf(mOutboxId, cats, items);
-
- item_count = cats->size() + items->size();
- }
-
- mOutboxItemCount = item_count;
- }
- else
- {
- // If there's no outbox, the number of items in it should be set to 0 for consistency
- mOutboxItemCount = 0;
- }
-
- if (!mImportBusy)
- {
- updateFolderCountStatus();
- }
-}
-
-void LLFloaterOutbox::updateFolderCountStatus()
-{
- if (mOutboxInventoryPanel.get() && mOutboxId.notNull())
- {
- switch (mOutboxItemCount)
- {
- case 0: setStatusString(getString("OutboxFolderCount0")); break;
- case 1: setStatusString(getString("OutboxFolderCount1")); break;
- default:
- {
- std::string item_count_str = llformat("%d", mOutboxItemCount);
-
- LLStringUtil::format_map_t args;
- args["[NUM]"] = item_count_str;
-
- setStatusString(getString("OutboxFolderCountN", args));
- break;
- }
- }
- }
-
- mImportButton->setEnabled(mOutboxItemCount > 0);
-}
-
-void LLFloaterOutbox::updateView()
-{
- updateFolderCount();
- LLInventoryPanel* panel = mOutboxInventoryPanel.get();
-
- if (mOutboxItemCount > 0)
- {
- panel->setVisible(TRUE);
- mInventoryPlaceholder->setVisible(FALSE);
- mOutboxTopLevelDropZone->setVisible(TRUE);
- }
- else
- {
- if (panel)
- {
- panel->setVisible(FALSE);
- }
-
- // Show the drop zone if there is an outbox folder
- mOutboxTopLevelDropZone->setVisible(mOutboxId.notNull());
-
- mInventoryPlaceholder->setVisible(TRUE);
-
- std::string outbox_text;
- std::string outbox_title;
- std::string outbox_tooltip;
-
- const LLSD& subs = getMarketplaceStringSubstitutions();
- U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus();
-
- if (mOutboxId.notNull())
- {
- // Does the outbox needs recreation?
- if ((mOutboxInventoryPanel.get() == NULL) || !gInventory.getCategory(mOutboxId))
- {
- setupOutbox();
- }
- // "Outbox is empty!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxNoItems", subs);
- outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip");
- }
- else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING)
- {
- // "Initializing!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxInitializing", subs);
- outbox_title = LLTrans::getString("InventoryOutboxInitializingTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip");
- }
- else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT)
- {
- // "Not a merchant!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxNotMerchant", subs);
- outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip");
- }
- else
- {
- // "Errors!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxError", subs);
- outbox_title = LLTrans::getString("InventoryOutboxErrorTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
- }
-
- mInventoryText->setValue(outbox_text);
- mInventoryTitle->setValue(outbox_title);
- mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip);
- }
-}
-
-bool isAccepted(EAcceptance accept)
-{
- return (accept >= ACCEPT_YES_COPY_SINGLE);
-}
-
-BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- if ((mOutboxInventoryPanel.get() == NULL) ||
- (mWindowShade && mWindowShade->isShown()) ||
- LLMarketplaceInventoryImporter::getInstance()->isImportInProgress() ||
- mOutboxId.isNull())
- {
- return FALSE;
- }
-
- LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- BOOL handled = (handled_view != NULL);
-
- // Determine if the mouse is inside the inventory panel itself or just within the floater
- bool pointInInventoryPanel = false;
- bool pointInInventoryPanelChild = false;
- LLInventoryPanel* panel = mOutboxInventoryPanel.get();
- LLFolderView* root_folder = panel->getRootFolder();
- if (panel->getVisible())
- {
- S32 inv_x, inv_y;
- localPointToOtherView(x, y, &inv_x, &inv_y, panel);
-
- pointInInventoryPanel = panel->getRect().pointInRect(inv_x, inv_y);
-
- LLView * inventory_panel_child_at_point = panel->childFromPoint(inv_x, inv_y, true);
- pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder);
- }
-
- // Pass all drag and drop for this floater to the outbox inventory control
- if (!handled || !isAccepted(*accept))
- {
- // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel
- // (otherwise the inventory panel itself will handle the drag and drop operation, without any override)
- if (!pointInInventoryPanel)
- {
- handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
-
- mOutboxTopLevelDropZone->setBackgroundVisible(handled && !drop && isAccepted(*accept));
- }
- else
- {
- mOutboxTopLevelDropZone->setBackgroundVisible(!pointInInventoryPanelChild);
- }
-
- return handled;
-}
-
-BOOL LLFloaterOutbox::handleHover(S32 x, S32 y, MASK mask)
-{
- mOutboxTopLevelDropZone->setBackgroundVisible(FALSE);
-
- return LLFloater::handleHover(x, y, mask);
-}
-
-void LLFloaterOutbox::onMouseLeave(S32 x, S32 y, MASK mask)
-{
- mOutboxTopLevelDropZone->setBackgroundVisible(FALSE);
-
- LLFloater::onMouseLeave(x, y, mask);
-}
-
-void LLFloaterOutbox::onImportButtonClicked()
-{
- if (mOutboxInventoryPanel.get())
- {
- mOutboxInventoryPanel.get()->clearSelection();
- }
-
- mImportBusy = LLMarketplaceInventoryImporter::instance().triggerImport();
-}
-
-void LLFloaterOutbox::onOutboxChanged()
-{
- LLViewerInventoryCategory* category = gInventory.getCategory(mOutboxId);
- if (mOutboxId.notNull() && category)
- {
- fetchOutboxContents();
- updateView();
- }
- else
- {
- cleanOutbox();
- }
-}
-
-void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content)
-{
- if (status == MarketplaceErrorCodes::IMPORT_DONE)
- {
- LLNotificationsUtil::add("OutboxImportComplete");
- }
- else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)
- {
- const LLSD& subs = getMarketplaceStringSubstitutions();
-
- LLNotificationsUtil::add("OutboxImportHadErrors", subs);
- }
- else
- {
- char status_string[16];
- sprintf(status_string, "%d", status);
-
- LLSD subs;
- subs["[ERROR_CODE]"] = status_string;
-
- LLNotificationsUtil::add("OutboxImportFailed", subs);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::importStatusChanged(bool inProgress)
-{
- if (mOutboxId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT))
- {
- setupOutbox();
- }
-
- if (inProgress)
- {
- if (mImportBusy)
- {
- setStatusString(getString("OutboxImporting"));
- }
- else
- {
- setStatusString(getString("OutboxInitializing"));
- }
-
- mImportBusy = true;
- mImportButton->setEnabled(false);
- mInventoryImportInProgress->setVisible(true);
- }
- else
- {
- setStatusString("");
- mImportBusy = false;
- mImportButton->setEnabled(mOutboxItemCount > 0);
- mInventoryImportInProgress->setVisible(false);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content)
-{
- if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
- {
- char status_string[16];
- sprintf(status_string, "%d", status);
-
- LLSD subs;
- subs["[ERROR_CODE]"] = status_string;
-
- LLNotificationsUtil::add("OutboxInitFailed", subs);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::showNotification(const LLNotificationPtr& notification)
-{
- LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- llassert(notification_handler);
-
- notification_handler->processNotification(notification);
-}
-
-
-
diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h
deleted file mode 100755
index 2cf69fc3cc..0000000000
--- a/indra/newview/llfloateroutbox.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file llfloateroutbox.h
- * @brief Implementation of the merchant outbox window
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATEROUTBOX_H
-#define LL_LLFLOATEROUTBOX_H
-
-#include "llfloater.h"
-#include "llfoldertype.h"
-#include "llinventoryfilter.h"
-#include "llnotificationptr.h"
-
-
-class LLButton;
-class LLInventoryCategoriesObserver;
-class LLInventoryCategoryAddedObserver;
-class LLInventoryPanel;
-class LLLoadingIndicator;
-class LLNotification;
-class LLTextBox;
-class LLView;
-class LLWindowShade;
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLFloaterOutbox
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLFloaterOutbox : public LLFloater
-{
-public:
- LLFloaterOutbox(const LLSD& key);
- ~LLFloaterOutbox();
-
- void initializeMarketPlace();
-
- // virtuals
- BOOL postBuild();
- BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg);
-
- void showNotification(const LLNotificationPtr& notification);
-
- BOOL handleHover(S32 x, S32 y, MASK mask);
- void onMouseLeave(S32 x, S32 y, MASK mask);
-
-protected:
- void setupOutbox();
- void cleanOutbox();
- void fetchOutboxContents();
-
- void importReportResults(U32 status, const LLSD& content);
- void importStatusChanged(bool inProgress);
- void initializationReportError(U32 status, const LLSD& content);
-
- void onClose(bool app_quitting);
- void onOpen(const LLSD& key);
-
- void onFocusReceived();
-
- void onImportButtonClicked();
- void onOutboxChanged();
-
- void setStatusString(const std::string& statusString);
-
- void updateFolderCount();
- void updateFolderCountStatus();
- void updateView();
-
-private:
- LLInventoryCategoriesObserver * mCategoriesObserver;
- LLInventoryCategoryAddedObserver * mCategoryAddedObserver;
-
- bool mImportBusy;
- LLButton * mImportButton;
-
- LLTextBox * mInventoryFolderCountText;
- LLView * mInventoryImportInProgress;
- LLView * mInventoryPlaceholder;
- LLTextBox * mInventoryText;
- LLTextBox * mInventoryTitle;
-
- LLUUID mOutboxId;
- LLHandle<LLInventoryPanel> mOutboxInventoryPanel;
- U32 mOutboxItemCount;
- LLPanel * mOutboxTopLevelDropZone;
-
- LLWindowShade * mWindowShade;
-};
-
-#endif // LL_LLFLOATEROUTBOX_H
diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp
index 16bb449fdb..cb67787af3 100755
--- a/indra/newview/llfloaterperms.cpp
+++ b/indra/newview/llfloaterperms.cpp
@@ -38,6 +38,8 @@
#include "llsdserialize.h"
#include "llvoavatar.h"
#include "llcorehttputil.h"
+#include "lleventfilter.h"
+#include "lleventcoro.h"
LLFloaterPerms::LLFloaterPerms(const LLSD& seed)
: LLFloater(seed)
@@ -167,11 +169,15 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)
xfer->setEnabled(copyable);
}
+const int MAX_HTTP_RETRIES = 5;
+const float RETRY_TIMEOUT = 5.0;
+
void LLFloaterPermsDefault::sendInitialPerms()
{
if(!mCapSent)
{
updateCap();
+ setCapSent(true);
}
}
@@ -193,7 +199,8 @@ void LLFloaterPermsDefault::updateCap()
/*static*/
void LLFloaterPermsDefault::updateCapCoro(std::string url)
{
- static std::string previousReason;
+ int retryCount = 0;
+ std::string previousReason;
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
@@ -215,23 +222,37 @@ void LLFloaterPermsDefault::updateCapCoro(std::string url)
LL_CONT << sent_perms_log.str() << LL_ENDL;
}
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ while (true)
+ {
+ ++retryCount;
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (!status)
- {
- const std::string& reason = status.toString();
- // Do not display the same error more than once in a row
- if (reason != previousReason)
+ if (!status)
{
- previousReason = reason;
- LLSD args;
- args["REASON"] = reason;
- LLNotificationsUtil::add("DefaultObjectPermissions", args);
+ LLEventTimeout timeout;
+
+ const std::string& reason = status.toString();
+ // Do not display the same error more than once in a row
+ if (reason != previousReason)
+ {
+ previousReason = reason;
+ LLSD args;
+ args["REASON"] = reason;
+ LLNotificationsUtil::add("DefaultObjectPermissions", args);
+ }
+
+ timeout.eventAfter(RETRY_TIMEOUT, LLSD());
+ llcoro::suspendUntilEventOn(timeout);
+ if (retryCount < MAX_HTTP_RETRIES)
+ continue;
+
+ LL_WARNS("ObjectPermissionsFloater") << "Unable to send default permissions. Giving up for now." << LL_ENDL;
+ return;
}
- return;
+ break;
}
// Since we have had a successful POST call be sure to display the next error message
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ee4396758e..dac610eda1 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -49,6 +49,7 @@
//#include "llfirstuse.h"
#include "llfloaterreg.h"
#include "llfloaterabout.h"
+#include "llfavoritesbar.h"
#include "llfloaterhardwaresettings.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloaterimsession.h"
@@ -1919,7 +1920,7 @@ BOOL LLPanelPreference::postBuild()
}
if (hasChild("favorites_on_login_check", TRUE))
{
- getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2));
+ getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2));
bool show_favorites_at_login = LLPanelLogin::getShowFavorites();
getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login);
}
@@ -2004,11 +2005,15 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v
}
}
-void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value)
+void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value)
{
- if (checkbox && checkbox->getValue())
+ if (checkbox)
{
- LLNotificationsUtil::add("FavoritesOnLogin");
+ LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean());
+ if(checkbox->getValue())
+ {
+ LLNotificationsUtil::add("FavoritesOnLogin");
+ }
}
}
@@ -2235,6 +2240,11 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
void LLFloaterPreferenceProxy::onClose(bool app_quitting)
{
+ if(app_quitting)
+ {
+ cancel();
+ }
+
if (mSocksSettingsDirty)
{
@@ -2334,6 +2344,11 @@ void LLFloaterPreferenceProxy::onBtnCancel()
cancel();
}
+void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+}
+
void LLFloaterPreferenceProxy::cancel()
{
@@ -2344,7 +2359,7 @@ void LLFloaterPreferenceProxy::cancel()
LLSD ctrl_value = iter->second;
control->set(ctrl_value);
}
-
+ mSocksSettingsDirty = false;
closeFloater();
}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 7bf6ae7d79..04e5e37731 100755
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -229,7 +229,7 @@ private:
//for "Only friends and groups can call or IM me"
static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&);
//for "Show my Favorite Landmarks at Login"
- static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value);
+ static void handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value);
typedef std::map<std::string, LLColor4> string_color_map_t;
string_color_map_t mSavedColors;
@@ -269,6 +269,7 @@ protected:
void saveSettings();
void onBtnOk();
void onBtnCancel();
+ void onClickCloseBtn(bool app_quitting = false);
void onChangeSocksSettings();
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 37e934429f..94f3a45d88 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -3586,29 +3586,6 @@ void LLPanelRegionExperiences::processResponse( const LLSD& content )
}
-
-class LLRegionExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- typedef boost::function<void (const LLSD&)> callback_t;
-
- callback_t mCallback;
-
- LLRegionExperienceResponder(callback_t callback) : mCallback(callback) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- mCallback(getContent());
- }
-
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
-
// Used for both access add and remove operations, depending on the flag
// passed in (ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE, etc.)
// static
@@ -3691,6 +3668,13 @@ void LLPanelRegionExperiences::infoCallback(LLHandle<LLPanelRegionExperiences> h
}
}
+/*static*/
+std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* region, const std::string &cap)
+{
+ // region->getHandle() How to get a region * from a handle?
+
+ return region->getCapability(cap);
+}
bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
{
@@ -3715,13 +3699,10 @@ bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
mTrusted->loading();
mTrusted->setReadonly(!allow_modify);
- std::string url = region->getCapability("RegionExperiences");
- if (!url.empty())
- {
- LLHTTPClient::get(url, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
- getDerivedHandle<LLPanelRegionExperiences>(), _1)));
- }
- return LLPanelRegionInfo::refreshFromRegion(region);
+ LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
+ boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
+
+ return LLPanelRegionInfo::refreshFromRegion(region);
}
LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
@@ -3739,18 +3720,15 @@ LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
BOOL LLPanelRegionExperiences::sendUpdate()
{
LLViewerRegion* region = gAgent.getRegion();
- std::string url = region->getCapability("RegionExperiences");
- if (!url.empty())
- {
- LLSD content;
- content["allowed"]=addIds(mAllowed);
- content["blocked"]=addIds(mBlocked);
- content["trusted"]=addIds(mTrusted);
+ LLSD content;
- LLHTTPClient::post(url, content, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
- getDerivedHandle<LLPanelRegionExperiences>(), _1)));
- }
+ content["allowed"]=addIds(mAllowed);
+ content["blocked"]=addIds(mBlocked);
+ content["trusted"]=addIds(mTrusted);
+
+ LLExperienceCache::instance().setRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
+ content, boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
return TRUE;
}
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 90f115faaf..3c74618fff 100755
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -479,6 +479,8 @@ public:
private:
void refreshRegionExperiences();
+ static std::string regionCapabilityQuery(LLViewerRegion* region, const std::string &cap);
+
LLPanelExperienceListEditor* setupList(const char* control_name, U32 add_id, U32 remove_id);
static LLSD addIds( LLPanelExperienceListEditor* panel );
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 714d8d0e8f..ed6f4ede9f 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -35,6 +35,7 @@
#include "llassetstorage.h"
#include "llavatarnamecache.h"
#include "llcachename.h"
+#include "llcheckboxctrl.h"
#include "llfontgl.h"
#include "llimagej2c.h"
#include "llinventory.h"
@@ -191,6 +192,7 @@ BOOL LLFloaterReporter::postBuild()
mOwnerName = LLStringUtil::null;
getChild<LLUICtrl>("summary_edit")->setFocus(TRUE);
+ getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE);
mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString();
@@ -268,7 +270,7 @@ void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
if (LLUUID::null != mExperienceID)
{
- const LLSD& experience = LLExperienceCache::getInstance()->get(mExperienceID);
+ const LLSD& experience = LLExperienceCache::instance().get(mExperienceID);
std::stringstream desc;
if(experience.isDefined())
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index 14719a77f9..7b8fc5b35b 100755
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -220,7 +220,7 @@ void LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro(std::string url
postData["parcel_id"] = mParcelId;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -260,7 +260,7 @@ void LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptSummaryCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -312,7 +312,7 @@ void LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptDetailsCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -963,7 +963,7 @@ void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 16fa4684ab..afec981d56 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -663,14 +663,20 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)
{
LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
+ LLSnapshotLivePreview* previewp = getPreviewView(view);
- if (!view || !check_box)
+ if (!view || !check_box || !previewp)
{
return;
}
gSavedSettings.setBOOL("UseFreezeFrame", check_box->get());
+ if (check_box->get())
+ {
+ previewp->prepareFreezeFrame();
+ }
+
updateLayout(view);
}
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index 6dc08417d7..5fa4441914 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -44,6 +44,7 @@
#include "message.h"
#include "llstartup.h" // login_alert_done
#include "llcorehttputil.h"
+#include "llfloaterreg.h"
LLFloaterTOS::LLFloaterTOS(const LLSD& data)
: LLModalDialog( data["message"].asString() ),
@@ -88,6 +89,12 @@ BOOL LLFloaterTOS::postBuild()
// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
// Store the URL separately and navigate here instead.
web_browser->navigateTo( getString( "loading_url" ) );
+ LLPluginClassMedia* media_plugin = web_browser->getMediaPlugin();
+ if (media_plugin)
+ {
+ // All links from tos_html should be opened in external browser
+ media_plugin->setOverrideClickTarget("_external");
+ }
}
return TRUE;
@@ -189,8 +196,10 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
mLoadingScreenLoaded = true;
std::string url(getString("real_url"));
+ LLHandle<LLFloater> handle = getHandle();
+
LLCoros::instance().launch("LLFloaterTOS::testSiteIsAliveCoro",
- boost::bind(&LLFloaterTOS::testSiteIsAliveCoro, this, url));
+ boost::bind(&LLFloaterTOS::testSiteIsAliveCoro, handle, url));
}
else if(mRealNavigateBegun)
{
@@ -202,7 +211,7 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
}
}
-void LLFloaterTOS::testSiteIsAliveCoro(std::string url)
+void LLFloaterTOS::testSiteIsAliveCoro(LLHandle<LLFloater> handle, std::string url)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
@@ -210,18 +219,31 @@ void LLFloaterTOS::testSiteIsAliveCoro(std::string url)
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
httpOpts->setWantHeaders(true);
- LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LL_INFOS("testSiteIsAliveCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- // double not.
- // First ! returns a boolean error status, second ! is true if success result.
- setSiteIsAlive(!!status);
+ if (handle.isDead())
+ {
+ LL_WARNS("testSiteIsAliveCoro") << "Dialog canceled before response." << LL_ENDL;
+ return;
+ }
+
+ LLFloaterTOS *that = dynamic_cast<LLFloaterTOS *>(handle.get());
+
+ if (that)
+ that->setSiteIsAlive(static_cast<bool>(status));
+ else
+ {
+ LL_WARNS("testSiteIsAliveCoro") << "Handle was not a TOS floater." << LL_ENDL;
+ }
}
diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h
index 2748b20513..e70c9f24af 100755
--- a/indra/newview/llfloatertos.h
+++ b/indra/newview/llfloatertos.h
@@ -62,7 +62,7 @@ public:
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
private:
- void testSiteIsAliveCoro(std::string url);
+ static void testSiteIsAliveCoro(LLHandle<LLFloater> handle, std::string url);
std::string mMessage;
bool mLoadingScreenLoaded;
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 965d29b09c..b1316e386d 100755
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -42,41 +42,6 @@
#include "llnotificationsutil.h"
#include "llradiogroup.h"
-class EnteredKeyVerifier : public LLTranslate::KeyVerificationReceiver
-{
-public:
- EnteredKeyVerifier(LLTranslate::EService service, bool alert)
- : LLTranslate::KeyVerificationReceiver(service)
- , mAlert(alert)
- {
- }
-
-private:
- /*virtual*/ void setVerificationStatus(bool ok)
- {
- LLFloaterTranslationSettings* floater =
- LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
-
- if (!floater)
- {
- LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL;
- return;
- }
-
- switch (getService())
- {
- case LLTranslate::SERVICE_BING:
- floater->setBingVerified(ok, mAlert);
- break;
- case LLTranslate::SERVICE_GOOGLE:
- floater->setGoogleVerified(ok, mAlert);
- break;
- }
- }
-
- bool mAlert;
-};
-
LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
: LLFloater(key)
, mMachineTranslationCB(NULL)
@@ -231,11 +196,34 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
mOKBtn->setEnabled(!on || service_verified);
}
+/*static*/
+void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert)
+{
+ LLFloaterTranslationSettings* floater =
+ LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
+
+ if (!floater)
+ {
+ LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL;
+ return;
+ }
+
+ switch (service)
+ {
+ case LLTranslate::SERVICE_BING:
+ floater->setBingVerified(ok, alert);
+ break;
+ case LLTranslate::SERVICE_GOOGLE:
+ floater->setGoogleVerified(ok, alert);
+ break;
+ }
+}
+
+
void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert)
{
- LLTranslate::KeyVerificationReceiverPtr receiver =
- new EnteredKeyVerifier((LLTranslate::EService) service, alert);
- LLTranslate::verifyKey(receiver, key);
+ LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
+ boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
}
void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index b9bfd6265a..2a15eacded 100755
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -61,6 +61,8 @@ private:
void onBtnGoogleVerify();
void onBtnOK();
+ static void setVerificationStatus(int service, bool alert, bool ok);
+
LLCheckBoxCtrl* mMachineTranslationCB;
LLComboBox* mLanguageCombo;
LLLineEditor* mBingAPIKeyEditor;
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index 6683a6e6e6..f2efef0c33 100755
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -220,7 +220,7 @@ void LLFloaterURLEntry::getMediaTypeCoro(std::string url, LLHandle<LLFloater> pa
LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 1b1c24b19a..ece3e10faa 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -284,12 +284,12 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
avatar_combo->selectFirstItem();
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
- avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
- location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
+ location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
mListSearchResults = childGetListInterface("search_results");
@@ -297,7 +297,7 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
landmark_combo->selectFirstItem();
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
- landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp
index 44eda4d6c0..e9f80b795a 100755
--- a/indra/newview/llfolderviewmodelinventory.cpp
+++ b/indra/newview/llfolderviewmodelinventory.cpp
@@ -109,6 +109,29 @@ bool LLFolderViewModelInventory::contentsReady()
return !LLInventoryModelBackgroundFetch::instance().folderFetchActive();
}
+bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder)
+{
+ LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
+ LLUUID cat_id = modelp->getUUID();
+ if (cat_id.isNull())
+ {
+ return false;
+ }
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ // don't need to check version - descendents_server == -1 if we have no data
+ S32 descendents_server = cat->getDescendentCount();
+ S32 descendents_actual = cat->getViewerDescendentCount();
+ if (descendents_server == descendents_actual
+ || (descendents_actual > 0 && descendents_server == -1)) // content was loaded in previous session
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
void LLFolderViewModelItemInventory::requestSort()
{
LLFolderViewModelItemCommon::requestSort();
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 0516fc3b4b..dea54cbe57 100755
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -115,6 +115,7 @@ public:
void sort(LLFolderViewFolder* folder);
bool contentsReady();
+ bool isFolderComplete(LLFolderViewFolder* folder);
bool startDrag(std::vector<LLFolderViewModelItem*>& items);
private:
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index eda9e51d23..def0f72433 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -41,7 +41,6 @@
#include "llui.h"
#include "message.h"
#include "roles_constants.h"
-#include "llhttpclient.h"
#include "lltransactiontypes.h"
#include "llstatusbar.h"
#include "lleconomy.h"
@@ -240,7 +239,8 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :
mRoleMemberDataComplete(false),
mGroupPropertiesDataComplete(false),
mPendingRoleMemberRequest(false),
- mAccessTime(0.0f)
+ mAccessTime(0.0f),
+ mPendingBanRequest(false)
{
mMemberVersion.generate();
}
@@ -762,8 +762,69 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
mBanList.erase(ban_id);
}
+void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid)
+{
+ if (!mMemberDataComplete ||
+ !mRoleDataComplete ||
+ !(mRoleMemberDataComplete && mMembers.size()))
+ {
+ LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL;
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+ if (!mMemberDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID);
+ }
+ if (!mRoleDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID);
+ }
+
+ return;
+ }
+
+ LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid));
+ if (mi == mMembers.end())
+ {
+ if (!mPendingBanRequest)
+ {
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading
+ }
+ else
+ {
+ mPendingBanRequest = false;
+ }
+
+ return;
+ }
+
+ mPendingBanRequest = false;
+
+ LLGroupMemberData* member_data = (*mi).second;
+ if (member_data && member_data->isInRole(mOwnerRole))
+ {
+ return; // can't ban group owner
+ }
+
+ std::vector<LLUUID> ids;
+ ids.push_back(participant_uuid);
+
+ LLGroupBanData ban_data;
+ createBanEntry(participant_uuid, ban_data);
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids);
+ LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids);
+ LLGroupMgr::getInstance()->sendGroupMembersRequest(mID);
+ LLSD args;
+ std::string name;
+ gCacheName->getFullName(participant_uuid, name);
+ args["AVATAR_NAME"] = name;
+ args["GROUP_NAME"] = mName;
+ LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+}
//
// LLGroupMgr
@@ -1246,6 +1307,11 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
group_datap->mChanged = TRUE;
LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA);
+
+ if (group_datap->mPendingBanRequest)
+ {
+ group_datap->banMemberById(group_datap->mPendingBanMemberID);
+ }
}
// static
@@ -1871,7 +1937,7 @@ void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId)
std::string finalUrl = url + "?group_id=" + groupId.asString();
- LLSD result = httpAdapter->getAndYield(httpRequest, finalUrl);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -1922,7 +1988,7 @@ void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId,
LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(httpRequest, finalUrl, postData, httpOptions, httpHeaders);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, finalUrl, postData, httpOptions, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -2042,7 +2108,7 @@ void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId)
LLSD postData = LLSD::emptyMap();
postData["group_id"] = groupId;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -2109,11 +2175,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
- // If we have no members, there's no reason to do anything else
- S32 num_members = content["member_count"];
- if(num_members < 1)
- return;
-
LLUUID group_id = content["group_id"].asUUID();
LLGroupMgrGroupData* group_datap = getGroupData(group_id);
@@ -2123,6 +2184,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
+ // If we have no members, there's no reason to do anything else
+ S32 num_members = content["member_count"];
+ if (num_members < 1)
+ {
+ LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL;
+ // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237
+ group_datap->mMemberDataComplete = true;
+ group_datap->mChanged = TRUE;
+ LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+ return;
+ }
+
group_datap->mMemberCount = num_members;
LLSD member_list = content["members"];
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index fd0c2de854..e5ce768035 100755
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -151,7 +151,7 @@ public:
const uuid_vec_t& getRoleMembers() const { return mMemberIDs; }
S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE);
- S32 getTotalMembersInRole() { return mMemberIDs.size(); }
+ S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225
LLRoleData getRoleData() const { return mRoleData; }
void setRoleData(LLRoleData data) { mRoleData = data; }
@@ -271,8 +271,8 @@ public:
void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData());
void removeBanEntry(const LLUUID& ban_id);
+ void banMemberById(const LLUUID& participant_uuid);
-
public:
typedef std::map<LLUUID,LLGroupMemberData*> member_list_t;
typedef std::map<LLUUID,LLGroupRoleData*> role_list_t;
@@ -304,6 +304,9 @@ public:
S32 mMemberCount;
S32 mRoleCount;
+ bool mPendingBanRequest;
+ LLUUID mPendingBanMemberID;
+
protected:
void sendRoleChanges();
void cancelRoleChanges();
diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp
index e2e151eb63..6a2daeeb90 100755
--- a/indra/newview/llhttpretrypolicy.cpp
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -25,9 +25,23 @@
*/
#include "llviewerprecompiledheaders.h"
-
#include "llhttpretrypolicy.h"
+namespace
+{
+ // Moved from httpconstants.h... only used in this file.
+ bool isHttpServerErrorStatus(S32 status)
+ {
+ // Status 499 is sometimes used for re-interpreted status 2xx errors.
+ // Allow retry of these, since we don't have enough information in this
+ // context to know if this will always fail.
+ if (HTTP_INTERNAL_ERROR == status) return true;
+
+ // Check for status 5xx.
+ return((500 <= status) && (status < 600));
+ }
+}
+
LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx):
mMinDelay(min_delay),
mMaxDelay(max_delay),
@@ -140,3 +154,34 @@ bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const
seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX;
return mShouldRetry;
}
+
+// Moved from httpconstants. Only used by this file.
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+/*static*/
+bool LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
+{
+ // *TODO: This needs testing! Not in use yet.
+ // Examples of Retry-After headers:
+ // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ // Retry-After: 120
+
+ // Check for number of seconds version, first:
+ char* end = 0;
+ // Parse as double
+ double seconds = std::strtod(retry_after.c_str(), &end);
+ if (end != 0 && *end == 0)
+ {
+ // Successful parse
+ seconds_to_wait = (F32)seconds;
+ return true;
+ }
+
+ // Parse rfc1123 date.
+ time_t date = curl_getdate(retry_after.c_str(), NULL);
+ if (-1 == date) return false;
+
+ seconds_to_wait = (F64)date - LLTimer::getTotalSeconds();
+
+ return true;
+}
+
diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h
index c0cc263546..af07b4afec 100755
--- a/indra/newview/llhttpretrypolicy.h
+++ b/indra/newview/llhttpretrypolicy.h
@@ -76,6 +76,8 @@ public:
// virtual
bool shouldRetry(F32& seconds_to_wait) const;
+ static bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
+
protected:
void init();
bool getRetryAfter(const LLSD& headers, F32& retry_header_time);
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 74f1cd0673..53b97a58c5 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -402,7 +402,7 @@ void startConfrenceCoro(std::string url,
postData["session-id"] = tempSessionId;
postData["params"] = agents;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -441,7 +441,7 @@ void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvit
postData["method"] = "accept invitation";
postData["session-id"] = sessionId;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 605f71f412..58411af089 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -121,12 +121,7 @@ bool isAddAction(const std::string& action)
bool isRemoveAction(const std::string& action)
{
- return ("take_off" == action || "detach" == action || "deactivate" == action);
-}
-
-bool isMarketplaceCopyAction(const std::string& action)
-{
- return (("copy_to_outbox" == action) || ("move_to_outbox" == action));
+ return ("take_off" == action || "detach" == action);
}
bool isMarketplaceSendAction(const std::string& action)
@@ -777,14 +772,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
{
items.push_back(std::string("Marketplace Separator"));
- if (gMenuHolder->getChild<LLView>("MerchantOutbox")->getVisible())
- {
- items.push_back(std::string("Merchant Copy"));
- if (!canListOnOutboxNow())
- {
- disabled_items.push_back(std::string("Merchant Copy"));
- }
- }
if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible())
{
items.push_back(std::string("Marketplace Copy"));
@@ -799,8 +786,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
}
- // Don't allow items to be pasted directly into the COF or the inbox/outbox
- if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder())
+ // Don't allow items to be pasted directly into the COF or the inbox
+ if (!isCOFFolder() && !isInboxFolder())
{
items.push_back(std::string("Paste"));
}
@@ -838,10 +825,6 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else
{
items.push_back(std::string("Share"));
@@ -915,15 +898,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
return;
}
- // "Remove link" and "Delete" are the same operation.
- if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
- {
- items.push_back(std::string("Remove Link"));
- }
- else
- {
- items.push_back(std::string("Delete"));
- }
+ items.push_back(std::string("Delete"));
if (!isItemRemovable())
{
@@ -942,19 +917,6 @@ void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
items.push_back(std::string("Open"));
}
-void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags,
- menuentry_vec_t &items,
- menuentry_vec_t &disabled_items)
-{
- items.push_back(std::string("Rename"));
- items.push_back(std::string("Delete"));
-
- if ((flags & FIRST_SELECTED_ITEM) == 0)
- {
- disabled_items.push_back(std::string("Rename"));
- }
-}
-
void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags,
menuentry_vec_t &items,
menuentry_vec_t &disabled_items)
@@ -1204,41 +1166,6 @@ BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
return gInventory.isObjectDescendentOf(mUUID, folder_id);
}
-BOOL LLInvFVBridge::isOutboxFolder() const
-{
- const LLUUID outbox_id = getOutboxFolder();
-
- if (outbox_id.isNull())
- {
- return FALSE;
- }
-
- return gInventory.isObjectDescendentOf(mUUID, outbox_id);
-}
-
-BOOL LLInvFVBridge::isOutboxFolderDirectParent() const
-{
- BOOL outbox_is_parent = FALSE;
-
- const LLInventoryCategory *cat = gInventory.getCategory(mUUID);
-
- if (cat)
- {
- const LLUUID outbox_id = getOutboxFolder();
-
- outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID()));
- }
-
- return outbox_is_parent;
-}
-
-const LLUUID LLInvFVBridge::getOutboxFolder() const
-{
- const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
-
- return outbox_id;
-}
-
BOOL LLInvFVBridge::isItemPermissive() const
{
return FALSE;
@@ -1495,56 +1422,6 @@ bool LLInvFVBridge::canListOnMarketplace() const
return true;
}
-// *TODO : Suppress canListOnOutboxNow() once we deprecate Merchant Outbox completely
-bool LLInvFVBridge::canListOnOutboxNow() const
-{
- bool can_list = true;
-
- // Do not allow listing while import is in progress
- if (LLMarketplaceInventoryImporter::instanceExists())
- {
- can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress();
- }
-
- const LLInventoryObject* obj = getInventoryObject();
- can_list &= (obj != NULL);
-
- if (can_list)
- {
- const LLUUID& object_id = obj->getLinkedUUID();
- can_list = object_id.notNull();
-
- if (can_list)
- {
- LLFolderViewFolder * object_folderp = mInventoryPanel.get() ? mInventoryPanel.get()->getFolderByID(object_id) : NULL;
- if (object_folderp)
- {
- can_list = !static_cast<LLFolderBridge*>(object_folderp->getViewModelItem())->isLoading();
- }
- }
-
- if (can_list)
- {
- // Get outbox id
- const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- LLFolderViewItem * outbox_itemp = mInventoryPanel.get() ? mInventoryPanel.get()->getItemByID(outbox_id) : NULL;
-
- if (outbox_itemp)
- {
- MASK mask = 0x0;
- BOOL drop = FALSE;
- EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
- void * cargo_data = (void *) obj;
- std::string tooltip_msg;
-
- can_list = outbox_itemp->getViewModelItem()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg);
- }
- }
- }
-
- return can_list;
-}
-
bool LLInvFVBridge::canListOnMarketplaceNow() const
{
bool can_list = true;
@@ -1714,16 +1591,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard();
return;
}
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy item to marketplace action!" << LL_ENDL;
-
- LLInventoryItem* itemp = model->getItem(mUUID);
- if (!itemp) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryItem* itemp = model->getItem(mUUID);
@@ -1810,7 +1677,9 @@ void LLItemBridge::restoreItem()
if(item)
{
LLInventoryModel* model = getInventoryModel();
- const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
+ bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+ const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
// do not restamp on restore.
LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
}
@@ -2437,7 +2306,8 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const
BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL drop,
std::string& tooltip_msg,
- BOOL user_confirm)
+ BOOL is_link,
+ BOOL user_confirm)
{
LLInventoryModel* model = getInventoryModel();
@@ -2455,13 +2325,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const LLUUID &cat_id = inv_cat->getUUID();
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID from_folder_uuid = inv_cat->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
- const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
@@ -2483,6 +2350,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
//--------------------------------------------------------------------------------
@@ -2520,8 +2388,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
if (is_movable && move_is_into_outfit)
{
+ if((mUUID == my_outifts_id) || (getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE))
+ {
+ is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT));
+ }
+ else
+ {
+ is_movable = false;
+ }
+ }
+ if(is_movable && move_is_into_current_outfit && is_link)
+ {
is_movable = FALSE;
- // tooltip?
}
if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
{
@@ -2602,9 +2480,9 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
- if (is_movable && (move_is_into_outbox || move_is_into_marketplacelistings))
+ if (is_movable && move_is_into_marketplacelistings)
{
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
LLViewerInventoryCategory * dest_folder = getCategory();
S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount());
is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);
@@ -2705,18 +2583,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
+
// if target is current outfit folder we use link
if (move_is_into_current_outfit &&
- inv_cat->getPreferredType() == LLFolderType::FT_NONE)
+ (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+ inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
{
// traverse category and add all contents to currently worn.
BOOL append = true;
LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
}
- else if (move_is_into_outbox && !move_is_from_outbox)
- {
- copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId());
- }
else if (move_is_into_marketplacelistings)
{
move_folder_to_marketplacelistings(inv_cat, mUUID);
@@ -2767,7 +2643,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else if (LLToolDragAndDrop::SOURCE_WORLD == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -2779,7 +2655,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -3296,16 +3172,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
removeSystemFolder();
}
#endif
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy folder to marketplace action!" << LL_ENDL;
-
- LLInventoryCategory * cat = gInventory.getCategory(mUUID);
- if (!cat) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryCategory * cat = gInventory.getCategory(mUUID);
@@ -3546,7 +3412,6 @@ void LLFolderBridge::perform_pasteFromClipboard()
if (model && isClipboardPasteable())
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
@@ -3554,7 +3419,6 @@ void LLFolderBridge::perform_pasteFromClipboard()
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_into_favorites = (mUUID == favorites_id);
@@ -3562,10 +3426,10 @@ void LLFolderBridge::perform_pasteFromClipboard()
LLClipboard::instance().pasteFromClipboard(objects);
LLViewerInventoryCategory * dest_folder = getCategory();
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
std::string error_msg;
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
int index = 0;
for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
{
@@ -3744,17 +3608,15 @@ void LLFolderBridge::pasteLinkFromClipboard()
if(model)
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
// Notify user of failure somehow -- play error sound? modal dialog?
return;
@@ -3875,10 +3737,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.clear(); // clear any items that used to exist
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if(isAgentInventory()) // do not allow creating in library
{
LLViewerInventoryCategory *cat = getCategory();
@@ -3886,7 +3744,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
// Not sure what the right thing is to do here.
if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT))
{
- if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox
+ if (!isInboxFolder()) // don't allow creation in inbox
{
// Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
@@ -3948,7 +3806,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
disabled_items.push_back(std::string("Delete System Folder"));
}
- if (!isOutboxFolder() && !isMarketplaceListingsFolder())
+ if (!isMarketplaceListingsFolder())
{
items.push_back(std::string("Share"));
if (!canShare())
@@ -3994,7 +3852,6 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
if (trash_id == mUUID) return;
if (isItemInTrash()) return;
if (!isAgentInventory()) return;
- if (isOutboxFolder()) return;
if (!isItemRemovable())
{
@@ -4141,7 +3998,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
if (linked_category)
{
- accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg);
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
}
}
else
@@ -4561,7 +4418,7 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c
if (option == 0) // YES
{
std::string tooltip_msg;
- dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE);
+ dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE, FALSE);
}
}
@@ -4588,7 +4445,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID from_folder_uuid = inv_item->getParentUUID();
@@ -4598,8 +4454,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
- const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id);
@@ -4675,9 +4529,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = can_move_to_landmarks(inv_item);
}
- else if (user_confirm && (move_is_into_outbox || move_is_into_marketplacelistings))
+ else if (user_confirm && move_is_into_marketplacelistings)
{
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
LLViewerInventoryCategory * dest_folder = getCategory();
accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());
}
@@ -4762,19 +4616,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
dropToOutfit(inv_item, move_is_into_current_outfit);
}
- // MERCHANT OUTBOX folder
- // Move the item
- else if (move_is_into_outbox)
- {
- if (move_is_from_outbox)
- {
- move_item_within_outbox(inv_item, mUUID, LLToolDragAndDrop::getOperationId());
- }
- else
- {
- copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId());
- }
- }
// MARKETPLACE LISTINGS folder
// Move the item
else if (move_is_into_marketplacelistings)
@@ -4861,7 +4702,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = FALSE;
}
- else if (move_is_into_outbox || move_is_into_marketplacelistings)
+ else if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -4899,7 +4740,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -4933,7 +4774,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = TRUE;
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -5102,10 +4943,6 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5175,11 +5012,7 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t items;
menuentry_vec_t disabled_items;
- if (isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -5256,11 +5089,7 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t disabled_items;
LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL;
- if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -5554,10 +5383,6 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5760,7 +5585,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action)
gInventory.updateItem(item);
gInventory.notifyObservers();
}
- else if (isRemoveAction(action))
+ else if ("deactivate" == action || isRemoveAction(action))
{
LLGestureMgr::instance().deactivateGesture(mUUID);
@@ -5846,10 +5671,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5906,11 +5727,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t disabled_items;
LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL;
- if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -6171,10 +5988,6 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -6382,12 +6195,8 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action
void LLWearableBridge::openItem()
{
- LLViewerInventoryItem* item = getItem();
-
- if (item)
- {
- LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
- }
+ performAction(getInventoryModel(),
+ get_is_item_worn(mUUID) ? "take_off" : "wear");
}
void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
@@ -6399,10 +6208,6 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -6705,10 +6510,6 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
items.push_back(std::string("Restore Item"));
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 7e7cf9c7dd..9053c61171 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -77,7 +77,6 @@ public:
bool canShare() const;
bool canListOnMarketplace() const;
- bool canListOnOutboxNow() const;
bool canListOnMarketplaceNow() const;
//--------------------------------------------------------------------
@@ -145,9 +144,6 @@ protected:
virtual void addDeleteContextMenuOptions(menuentry_vec_t &items,
menuentry_vec_t &disabled_items);
virtual void addOpenRightClickMenuOption(menuentry_vec_t &items);
- virtual void addOutboxContextMenuOptions(U32 flags,
- menuentry_vec_t &items,
- menuentry_vec_t &disabled_items);
virtual void addMarketplaceContextMenuOptions(U32 flags,
menuentry_vec_t &items,
menuentry_vec_t &disabled_items);
@@ -164,9 +160,7 @@ protected:
BOOL isCOFFolder() const; // true if COF or descendant of
BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox
- BOOL isOutboxFolderDirectParent() const;
BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder
- const LLUUID getOutboxFolder() const;
virtual BOOL isItemPermissive() const;
static void changeItemParent(LLInventoryModel* model,
@@ -182,10 +176,6 @@ protected:
BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response);
BOOL perform_cutToClipboard();
-public:
- BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox
-
-protected:
LLHandle<LLInventoryPanel> mInventoryPanel;
LLFolderView* mRoot;
const LLUUID mUUID; // item id
@@ -274,7 +264,7 @@ public:
{}
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
- BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
+ BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 916e9ad8f3..e3cb4d57ef 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -782,11 +782,6 @@ void reset_inventory_filter()
}
}
-void open_outbox()
-{
- LLFloaterReg::showInstance("outbox");
-}
-
void open_marketplace_listings()
{
LLFloaterReg::showInstance("marketplace_listings");
@@ -808,157 +803,6 @@ LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
return created_folder_id;
}
-void move_to_outbox_cb_action(const LLSD& payload)
-{
- LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID());
- LLUUID dest_folder_id = payload["dest_folder_id"].asUUID();
-
- if (viitem)
- {
- // when moving item directly into outbox create folder with that name
- if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder_id = create_folder_for_item(viitem, dest_folder_id);
- }
-
- LLUUID parent = viitem->getParentUUID();
-
- gInventory.changeItemParent(
- viitem,
- dest_folder_id,
- false);
-
- LLUUID top_level_folder = payload["top_level_folder"].asUUID();
-
- if (top_level_folder != LLUUID::null)
- {
- LLViewerInventoryCategory* category;
-
- while (parent.notNull())
- {
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(parent,cat_array,item_array);
-
- LLUUID next_parent;
-
- category = gInventory.getCategory(parent);
-
- if (!category) break;
-
- next_parent = category->getParentUUID();
-
- if (cat_array->empty() && item_array->empty())
- {
- gInventory.removeCategory(parent);
- }
-
- if (parent == top_level_folder)
- {
- break;
- }
-
- parent = next_parent;
- }
- }
-
- open_outbox();
- }
-}
-
-void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id)
-{
- // Collapse links directly to items/folders
- LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
- LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory();
- if (linked_category != NULL)
- {
- copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id);
- }
- else
- {
- LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
- if (linked_item != NULL)
- {
- inv_item = (LLInventoryItem *) linked_item;
- }
-
- // Check for copy permissions
- if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
- {
- // when moving item directly into outbox create folder with that name
- if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder = create_folder_for_item(inv_item, dest_folder);
- }
-
- copy_inventory_item(gAgent.getID(),
- inv_item->getPermissions().getOwner(),
- inv_item->getUUID(),
- dest_folder,
- inv_item->getName(),
- LLPointer<LLInventoryCallback>(NULL));
-
- open_outbox();
- }
- else
- {
- LLSD payload;
- payload["item_id"] = inv_item->getUUID();
- payload["dest_folder_id"] = dest_folder;
- payload["top_level_folder"] = top_level_folder;
- payload["operation_id"] = operation_id;
-
- LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action);
- }
- }
-}
-
-void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id)
-{
- // when moving item directly into outbox create folder with that name
- if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder = create_folder_for_item(inv_item, dest_folder);
- }
-
- LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
-
- gInventory.changeItemParent(
- viewer_inv_item,
- dest_folder,
- false);
-}
-
-void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id)
-{
- LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName());
- gInventory.notifyObservers();
-
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array);
-
- // copy the vector because otherwise the iterator won't be happy if we delete from it
- LLInventoryModel::item_array_t item_array_copy = *item_array;
-
- for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
- {
- LLInventoryItem* item = *iter;
- copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id);
- }
-
- LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
-
- for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
- {
- LLViewerInventoryCategory* category = *iter;
- copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id);
- }
-
- open_outbox();
-}
-
///----------------------------------------------------------------------------
// Marketplace functions
//
@@ -975,7 +819,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid)
{
return -1;
}
- // If not a descendent of the marketplace listings root, then the nesting depth is -1 by definition
+ // If not a descendant of the marketplace listings root, then the nesting depth is -1 by definition
if (!gInventory.isObjectDescendentOf(cur_uuid, marketplace_listings_uuid))
{
return -1;
@@ -2473,7 +2317,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
LLSD args;
args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem");
- LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&onItemsRemovalConfirmation, _1, _2, root->getHandle()));
+ LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
// Note: marketplace listings will be updated in the callback if delete confirmed
return;
}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 6ae8fd0f13..649db4032d 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -75,10 +75,6 @@ void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory*
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
-void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id);
-void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id);
-void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id);
-
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
@@ -465,9 +461,9 @@ struct LLInventoryAction
static void removeItemFromDND(LLFolderView* root);
private:
- static void buildMarketplaceFolders(LLFolderView* root);
- static void updateMarketplaceFolders();
- static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
+ static void buildMarketplaceFolders(LLFolderView* root);
+ static void updateMarketplaceFolders();
+ static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
};
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 175ea22aa0..ab0df33051 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -614,7 +614,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv
LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -2456,7 +2456,7 @@ void LLInventoryModel::handleResponses(bool foreground)
LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
const std::string & url,
const LLSD & body,
- LLCore::HttpHandler * handler,
+ const LLCore::HttpHandler::ptr_t &handler,
const char * const message)
{
if (! mHttpRequestFG)
@@ -2485,7 +2485,6 @@ LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
<< ", Status: " << status.toTerseString()
<< " Reason: '" << status.toString() << "'"
<< LL_ENDL;
- delete handler;
}
return handle;
}
@@ -4051,9 +4050,6 @@ void LLInventoryModel::FetchItemHttpHandler::onCompleted(LLCore::HttpHandle hand
processData(body_llsd, response);
}
while (false);
-
- // Must delete on completion.
- delete this;
}
void LLInventoryModel::FetchItemHttpHandler::processData(LLSD & content, LLCore::HttpResponse * response)
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index e8977bc7d7..e1e6db19eb 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -35,7 +35,6 @@
#include "llassettype.h"
#include "llfoldertype.h"
#include "llframetimer.h"
-#include "llcurl.h"
#include "lluuid.h"
#include "llpermissionsflags.h"
#include "llviewerinventory.h"
@@ -81,6 +80,9 @@ public:
typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t;
typedef std::set<LLUUID> changed_items_t;
+ // Rider: This is using the old responder patter. It should be refactored to
+ // take advantage of coroutines.
+
// HTTP handler for individual item requests (inventory or library).
// Background item requests are derived from this in the background
// inventory system. All folder requests are also located there
@@ -564,7 +566,7 @@ public:
LLCore::HttpHandle requestPost(bool foreground,
const std::string & url,
const LLSD & body,
- LLCore::HttpHandler * handler,
+ const LLCore::HttpHandler::ptr_t &handler,
const char * const message);
private:
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 40edb13a80..4a77edc565 100755
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -513,7 +513,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
if (! url.empty())
{
- BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body, recursive_cats));
+ LLCore::HttpHandler::ptr_t handler(new BGFolderHttpHandler(folder_request_body, recursive_cats));
gInventory.requestPost(false, url, folder_request_body, handler, "Inventory Folder");
}
}
@@ -524,7 +524,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
if (! url.empty())
{
- BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body_lib, recursive_cats));
+ LLCore::HttpHandler::ptr_t handler(new BGFolderHttpHandler(folder_request_body_lib, recursive_cats));
gInventory.requestPost(false, url, folder_request_body_lib, handler, "Library Folder");
}
}
@@ -540,7 +540,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
{
LLSD body;
body["items"] = item_request_body;
- BGItemHttpHandler * handler(new BGItemHttpHandler(body));
+ LLCore::HttpHandler::ptr_t handler(new BGItemHttpHandler(body));
gInventory.requestPost(false, url, body, handler, "Inventory Item");
}
}
@@ -553,7 +553,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
{
LLSD body;
body["items"] = item_request_body_lib;
- BGItemHttpHandler * handler(new BGItemHttpHandler(body));
+ LLCore::HttpHandler::ptr_t handler(new BGItemHttpHandler(body));
gInventory.requestPost(false, url, body, handler, "Library Item");
}
}
@@ -647,9 +647,6 @@ void BGFolderHttpHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRes
processData(body_llsd, response);
}
while (false);
-
- // Must delete on completion.
- delete this;
}
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index d81401b59b..6c81378622 100755
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -237,7 +237,7 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
if (!url.empty())
{
body[i]["agent_id"] = gAgent.getID();
- LLInventoryModel::FetchItemHttpHandler * handler(new LLInventoryModel::FetchItemHttpHandler(body[i]));
+ LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body[i]));
gInventory.requestPost(true, url, body[i], handler, (i ? "Library Item" : "Inventory Item"));
continue;
}
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 5194cba891..02d378bc51 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1437,16 +1437,20 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask )
// Open selected items if enter key hit on the inventory panel
if (mask == MASK_NONE)
{
- //Don't allow attaching or opening items from Merchant Outbox
- LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
- if(folder_item)
- {
- LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
- if(bridge && bridge->isOutboxFolder() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
- {
- return handled;
- }
- }
+
+// @TODO$: Rider: This code is dead with Outbox, however should something similar be
+// done for VMM?
+//
+// //Don't allow attaching or opening items from Merchant Outbox
+// LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
+// if(folder_item)
+// {
+// LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+// if(bridge && bridge->is() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
+// {
+// return handled;
+// }
+// }
LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open");
handled = TRUE;
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 4e9947fca0..46c1ffa789 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -515,7 +515,7 @@ void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)
{
LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLSculptParams new_params(*old_params);
- new_params.setSculptTexture(new_id);
+ new_params.setSculptTexture(new_id, (*old_params).getSculptType());
object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE);
}
}
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index cf04c5f7a5..8d21fda8f9 100755
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -862,14 +862,11 @@ void LLLocationInputCtrl::refreshParcelIcons()
bool see_avs = current_parcel->getSeeAVs();
bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty);
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 7ddacf3033..4116e38f11 100755
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -804,6 +804,22 @@ bool LLLogChat::isNearbyTranscriptExist()
return false;
}
+bool LLLogChat::isAdHocTranscriptExist(std::string file_name)
+{
+ std::vector<std::string> list_of_transcriptions;
+ LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+
+ file_name = makeLogFileName(file_name);
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (transcript_file_name == file_name)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index ca597599dd..6022e539a9 100755
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -120,6 +120,7 @@ public:
static void deleteTranscripts();
static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
static bool isNearbyTranscriptExist();
+ static bool isAdHocTranscriptExist(std::string file_name);
static bool historyThreadsFinished(LLUUID session_id);
static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id);
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 407613d32c..85faa70552 100755
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -1677,12 +1677,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
@@ -1710,12 +1710,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 394db71fb9..b4259a456c 100755
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1285,12 +1285,12 @@ void LLManipTranslate::renderSnapGuides()
{
tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit));
- F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
-
- if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
+ /*if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
// add in off-axis offset
tick_start += (mSnapOffsetAxis * mSnapOffsetMeters);
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index f11d0f16da..dfa33b37ef 100755
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -30,7 +30,6 @@
#include "llagent.h"
#include "llbufferstream.h"
-#include "llhttpclient.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
@@ -48,605 +47,127 @@
#include "llcoros.h"
#include "llcorehttputil.h"
+#include "llsdutil.h"
//
// Helpers
//
-static std::string getMarketplaceDomain()
-{
- std::string domain = "secondlife.com";
-
- if (!LLGridManager::getInstance()->isInProductionGrid())
- {
- const std::string& grid_id = LLGridManager::getInstance()->getGridId();
- const std::string& grid_id_lower = utf8str_tolower(grid_id);
-
- if (grid_id_lower == "damballah")
- {
- domain = "secondlife-staging.com";
- }
- else
- {
- domain = llformat("%s.lindenlab.com", grid_id_lower.c_str());
- }
- }
-
- return domain;
-}
+namespace {
-static std::string getMarketplaceURL(const std::string& urlStringName)
-{
- LLStringUtil::format_map_t domain_arg;
- domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain();
-
- std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg);
-
- return marketplace_url;
-}
-
-LLSD getMarketplaceStringSubstitutions()
-{
- std::string marketplace_url = getMarketplaceURL("MarketplaceURL");
- std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore");
- std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard");
- std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports");
- std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore");
-
- LLSD marketplace_sub_map;
-
- marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url;
- marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create;
- marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info;
- marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard;
- marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports;
-
- return marketplace_sub_map;
-}
-
-// Get the version folder: if there is only one subfolder, we will use it as a version folder
-LLUUID getVersionFolderIfUnique(const LLUUID& folder_id)
-{
- LLUUID version_id = LLUUID::null;
- LLInventoryModel::cat_array_t* categories;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(folder_id, categories, items);
- if (categories->size() == 1)
- {
- version_id = categories->begin()->get()->getUUID();
- }
- else
+ static std::string getMarketplaceDomain()
{
- LLNotificationsUtil::add("AlertMerchantListingActivateRequired");
- }
- return version_id;
-}
+ std::string domain = "secondlife.com";
-///////////////////////////////////////////////////////////////////////////////
-// SLM Responders
-void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
-{
- LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL;
- if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]"))
- {
- // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing
- LLNotificationsUtil::add("MerchantUnprocessableEntity");
- }
- else
- {
- // Prompt the user with the warning (so they know why things are failing)
- LLSD subs;
- subs["[ERROR_REASON]"] = reason;
- // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though.
- subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : "");
- LLNotificationsUtil::add("MerchantTransactionFailed", subs);
- }
-}
-void log_SLM_infos(const std::string& request, U32 status, const std::string& body)
-{
- if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
- {
- LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL;
- }
-}
-void log_SLM_infos(const std::string& request, const std::string& url, const std::string& body)
-{
- if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
- {
- LL_INFOS("SLM") << "SLM API : Sending " << request << ". url : " << url << ", body : " << body << LL_ENDL;
- }
-}
-
-class LLSLMGetMerchantResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetMerchantResponder);
-public:
-
- LLSLMGetMerchantResponder() {}
-
-protected:
- virtual void httpFailure()
- {
- if (HTTP_NOT_FOUND == getStatus())
- {
- log_SLM_infos("Get /merchant", getStatus(), "User is not a merchant");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
- }
- else if (HTTP_SERVICE_UNAVAILABLE == getStatus())
+ if (!LLGridManager::getInstance()->isInProductionGrid())
{
- log_SLM_infos("Get /merchant", getStatus(), "Merchant is not migrated");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
- }
- else
- {
- log_SLM_warning("Get /merchant", getStatus(), getReason(), getContent().get("error_code"), getContent().get("error_description"));
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
- }
- }
-
- virtual void httpSuccess()
- {
- log_SLM_infos("Get /merchant", getStatus(), "User is a merchant");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT);
- }
-
-};
-
-class LLSLMGetListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetListingsResponder);
-public:
-
- LLSLMGetListingsResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Get /listings", getStatus(), getReason(), "", body);
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
+ const std::string& grid_id = LLGridManager::getInstance()->getGridId();
+ const std::string& grid_id_lower = utf8str_tolower(grid_id);
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Get /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Get /listings", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
- if (folder_id.notNull())
+ if (grid_id_lower == "damballah")
+ {
+ domain = "secondlife-staging.com";
+ }
+ else
{
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
+ domain = llformat("%s.lindenlab.com", grid_id_lower.c_str());
}
- it++;
}
-
- // Update all folders under the root
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- }
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMCreateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMCreateListingsResponder);
-public:
-
- LLSLMCreateListingsResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
+ return domain;
}
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+
+ static std::string getMarketplaceURL(const std::string& urlStringName)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Post /listings", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Post /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
+ LLStringUtil::format_map_t domain_arg;
+ domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain();
- log_SLM_infos("Post /listings", getStatus(), body);
+ std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg);
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
- it++;
- }
+ return marketplace_url;
}
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMGetListingResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetListingResponder);
-public:
-
- LLSLMGetListingResponder(const LLUUID& folder_id)
+ // Get the version folder: if there is only one subfolder, we will use it as a version folder
+ LLUUID getVersionFolderIfUnique(const LLUUID& folder_id)
{
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- if (getStatus() == 404)
- {
- // That listing does not exist -> delete its record from the local SLM data store
- LLMarketplaceData::instance().deleteListing(mExpectedFolderId, false);
- }
- else
- {
- log_SLM_warning("Get /listing", getStatus(), getReason(), "", body);
- }
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
+ LLUUID version_id = LLUUID::null;
+ LLInventoryModel::cat_array_t* categories;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(folder_id, categories, items);
+ if (categories->size() == 1)
{
- log_SLM_warning("Get /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
+ version_id = categories->begin()->get()->getUUID();
}
-
- log_SLM_infos("Get /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ else
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Update that listing
- LLMarketplaceData::instance().setListingID(folder_id, listing_id, false);
- LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false);
- LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false);
- LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
- LLMarketplaceData::instance().setCountOnHand(folder_id,count,false);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- it++;
+ LLNotificationsUtil::add("AlertMerchantListingActivateRequired");
}
+ return version_id;
}
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMUpdateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMUpdateListingsResponder);
-public:
-
- LLSLMUpdateListingsResponder(const LLUUID& folder_id, bool expected_listed_state, const LLUUID& expected_version_id)
+ ///////////////////////////////////////////////////////////////////////////////
+ // SLM Reporters
+ void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const LLSD& result)
{
- mExpectedFolderId = folder_id;
- mExpectedListedState = expected_listed_state;
- mExpectedVersionUUID = expected_version_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Put /listing", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
+ LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << ll_pretty_print_sd(result) << LL_ENDL;
+ if ((status == 422) && (result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT) &&
+ result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT].isArray() &&
+ result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT].size() > 4))
{
- log_SLM_warning("Put /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
+ // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing
+ LLNotificationsUtil::add("MerchantUnprocessableEntity");
}
-
- log_SLM_infos("Put /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ else
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Update that listing
- LLMarketplaceData::instance().setListingID(folder_id, listing_id, false);
- LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false);
- LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false);
- LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
- LLMarketplaceData::instance().setCountOnHand(folder_id,count,false);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- // Show a notification alert if what we got is not what we expected
- // (this actually doesn't result in an error status from the SLM API protocol)
- if ((mExpectedListedState != is_listed) || (mExpectedVersionUUID != version_id))
+ // Prompt the user with the warning (so they know why things are failing)
+ LLSD subs;
+ subs["[ERROR_REASON]"] = reason;
+ // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though.
+ std::string description;
+ if (result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT))
{
- LLSD subs;
- subs["[URL]"] = edit_url;
- LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs);
+ LLSD content = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
+ if (content.isArray())
+ {
+ for (LLSD::array_iterator it = content.beginArray(); it != content.endArray(); ++it)
+ {
+ if (!description.empty())
+ description += "\n";
+ description += (*it).asString();
+ }
+ }
+ else
+ {
+ description = content.asString();
+ }
}
-
- it++;
+ else
+ {
+ description = result.asString();
+ }
+ subs["[ERROR_DESCRIPTION]"] = description;
+ LLNotificationsUtil::add("MerchantTransactionFailed", subs);
}
- }
-private:
- LLUUID mExpectedFolderId;
- bool mExpectedListedState;
- LLUUID mExpectedVersionUUID;
-};
-class LLSLMAssociateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMAssociateListingsResponder);
-public:
-
- LLSLMAssociateListingsResponder(const LLUUID& folder_id, const LLUUID& source_folder_id)
- {
- mExpectedFolderId = folder_id;
- mSourceFolderId = source_folder_id;
}
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+
+ void log_SLM_infos(const std::string& request, U32 status, const std::string& body)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
- LLMarketplaceData::instance().setUpdating(mSourceFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- update_marketplace_category(mSourceFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Put /associate_inventory", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- update_marketplace_category(mSourceFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Put /associate_inventory", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Check that the listing ID is not already associated to some other record
- LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id);
- if (old_listing.notNull())
- {
- // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID)
- LLMarketplaceData::instance().deleteListing(old_listing);
- }
-
- // Add the new association
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- // The stock count needs to be updated with the new local count now
- LLMarketplaceData::instance().updateCountOnHand(folder_id,1);
-
- it++;
+ LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL;
}
-
- // Always update the source folder so its widget updates
- update_marketplace_category(mSourceFolderId, false);
}
-private:
- LLUUID mExpectedFolderId; // This is the folder now associated with the id.
- LLUUID mSourceFolderId; // This is the folder initially associated with the id. Can be LLUUI::null
-};
-class LLSLMDeleteListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMDeleteListingsResponder);
-public:
-
- LLSLMDeleteListingsResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+ void log_SLM_infos(const std::string& request, U32 status, const LLSD& body)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Delete /listing", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Delete /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Delete /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- LLMarketplaceData::instance().deleteListing(folder_id);
-
- it++;
- }
+ log_SLM_infos(request, status, std::string(ll_pretty_print_sd(body)));
}
-private:
- LLUUID mExpectedFolderId;
-};
-// SLM Responders End
-///////////////////////////////////////////////////////////////////////////////
+}
+
+#if 1
namespace LLMarketplaceImport
{
// Basic interface for this namespace
@@ -671,13 +192,8 @@ namespace LLMarketplaceImport
static S32 sImportResultStatus = 0;
static LLSD sImportResults = LLSD::emptyMap();
-#if 0
- static LLTimer slmGetTimer;
- static LLTimer slmPostTimer;
-#endif
// Responders
-#if 1
void marketplacePostCoro(std::string url)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
@@ -696,7 +212,7 @@ namespace LLMarketplaceImport
httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML);
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent());
- LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD(), httpOpts, httpHeaders);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -739,56 +255,6 @@ namespace LLMarketplaceImport
}
-
-#else
- class LLImportPostResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLImportPostResponder);
- public:
- LLImportPostResponder() : LLCurl::Responder() {}
-
- protected:
- /* virtual */ void httpCompleted()
- {
- slmPostTimer.stop();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] "
- << dumpResponse() << LL_ENDL;
- }
-
- S32 status = getStatus();
- if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) ||
- (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
- // MAINT-2301 : we determined we can safely ignore that error in that context
- (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL;
- }
- status = MarketplaceErrorCodes::IMPORT_DONE;
- }
-
- if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM POST : Clearing marketplace cookie due to client or server error" << LL_ENDL;
- }
- sMarketplaceCookie.clear();
- }
-
- sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);
- sImportPostPending = false;
- sImportResultStatus = status;
- sImportId = getContent();
- }
- };
-#endif
-
-#if 1
void marketplaceGetCoro(std::string url, bool buildHeaders)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
@@ -815,7 +281,7 @@ namespace LLMarketplaceImport
httpHeaders = LLViewerMedia::getHttpHeaders();
}
- LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -854,57 +320,6 @@ namespace LLMarketplaceImport
}
-#else
- class LLImportGetResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLImportGetResponder);
- public:
- LLImportGetResponder() : LLCurl::Responder() {}
-
- protected:
- /* virtual */ void httpCompleted()
- {
- const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
-
- if (!set_cookie_string.empty())
- {
- sMarketplaceCookie = set_cookie_string;
- }
-
- slmGetTimer.stop();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] "
- << dumpResponse() << LL_ENDL;
- }
-
- // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions
- // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty
- S32 status = getStatus();
- if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&
- (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&
- (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND))
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL;
- }
- sMarketplaceCookie.clear();
- }
- else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST))
- {
- LL_INFOS() << " SLM GET : Got error status = " << status << ", but marketplace cookie not cleared." << LL_ENDL;
- }
-
- sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
- sImportGetPending = false;
- sImportResultStatus = status;
- sImportResults = getContent();
- }
- };
-#endif
-
// Basic API
bool hasSessionCookie()
@@ -955,24 +370,9 @@ namespace LLMarketplaceImport
std::string url = getInventoryImportURL();
-#if 1
LLCoros::instance().launch("marketplaceGetCoro",
boost::bind(&marketplaceGetCoro, url, false));
-#else
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << LL_ENDL;
- LLSD headers = LLViewerMedia::getHeaders();
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM GET: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
-
- slmGetTimer.start();
- LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders());
-#endif
return true;
}
@@ -989,31 +389,9 @@ namespace LLMarketplaceImport
url += sImportId.asString();
-#if 1
LLCoros::instance().launch("marketplaceGetCoro",
boost::bind(&marketplaceGetCoro, url, true));
-#else
- // Make the headers for the post
- LLSD headers = LLSD::emptyMap();
- headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
- headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie;
- // *TODO: Why are we setting Content-Type for a GET request?
- headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
- headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM GET: pollStatus, LLHTTPClient::get, url = " << url << LL_ENDL;
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM GET: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
-
- slmGetTimer.start();
- LLHTTPClient::get(url, new LLImportGetResponder(), headers);
-#endif
return true;
}
@@ -1032,35 +410,13 @@ namespace LLMarketplaceImport
std::string url = getInventoryImportURL();
-#if 1
LLCoros::instance().launch("marketplacePostCoro",
boost::bind(&marketplacePostCoro, url));
-#else
- // Make the headers for the post
- LLSD headers = LLSD::emptyMap();
- headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
- headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive";
- headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie;
- headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML;
- headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM POST: triggerImport, LLHTTPClient::post, url = " << url << LL_ENDL;
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM POST: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
-
- slmPostTimer.start();
- LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers);
-#endif
return true;
}
}
-
+#endif
//
// Interface class
@@ -1362,6 +718,26 @@ LLMarketplaceData::~LLMarketplaceData()
gInventory.removeObserver(mInventoryObserver);
}
+
+LLSD LLMarketplaceData::getMarketplaceStringSubstitutions()
+{
+ std::string marketplace_url = getMarketplaceURL("MarketplaceURL");
+ std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore");
+ std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard");
+ std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports");
+ std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore");
+
+ LLSD marketplace_sub_map;
+
+ marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url;
+ marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create;
+ marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info;
+ marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard;
+ marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports;
+
+ return marketplace_sub_map;
+}
+
void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& cb)
{
if (mStatusUpdatedSignal == NULL)
@@ -1377,15 +753,60 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type&
}
else
{
- // Initiate SLM connection and set responder
- std::string url = getSLMConnectURL("/merchant");
- if (url != "")
+ mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
+
+ LLCoros::instance().launch("getMerchantStatus",
+ boost::bind(&LLMarketplaceData::getMerchantStatusCoro, this));
+ }
+}
+
+void LLMarketplaceData::getMerchantStatusCoro()
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setFollowRedirects(true);
+
+ std::string url = getSLMConnectURL("/merchant");
+ if (url.empty())
+ {
+ LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL;
+ }
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ S32 httpCode = status.getType();
+
+ if (httpCode == HTTP_NOT_FOUND)
+ {
+ log_SLM_infos("Get /merchant", httpCode, std::string("User is not a merchant"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
+ }
+ else if (httpCode == HTTP_SERVICE_UNAVAILABLE)
+ {
+ log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
+ }
+ else
{
- mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
- log_SLM_infos("LLHTTPClient::get", url, "");
- LLHTTPClient::get(url, new LLSLMGetMerchantResponder(), LLSD());
+ std::string err_code = result["error_code"].asString();
+ //std::string err_description = result["error_description"].asString();
+ log_SLM_warning("Get /merchant", httpCode, status.toString(), err_code, result["error_description"]);
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
}
+ return;
}
+
+ log_SLM_infos("Get /merchant", status.getType(), std::string("User is a merchant"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT);
}
void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb)
@@ -1400,151 +821,434 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot
// Get/Post/Put requests to the SLM Server using the SLM API
void LLMarketplaceData::getSLMListings()
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
+ const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ setUpdating(marketplaceFolderId, true);
+
+ LLCoros::instance().launch("getSLMListings",
+ boost::bind(&LLMarketplaceData::getSLMListingsCoro, this, marketplaceFolderId));
+}
+
+void LLMarketplaceData::getSLMListingsCoro(LLUUID folderId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
std::string url = getSLMConnectURL("/listings");
- log_SLM_infos("LLHTTPClient::get", url, "");
- const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- setUpdating(marketplacelistings_id,true);
- LLHTTPClient::get(url, new LLSLMGetListingsResponder(marketplacelistings_id), headers);
+
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Get /listings", status.getType(), status.toString(), "", result);
+ setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result);
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ if (folderUuid.notNull())
+ {
+ addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count);
+ }
+ }
+
+ // Update all folders under the root
+ setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
}
-void LLMarketplaceData::getSLMListing(S32 listing_id)
+void LLMarketplaceData::getSLMListing(S32 listingId)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::get", url, "");
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- setUpdating(folder_id,true);
- LLHTTPClient::get(url, new LLSLMGetListingResponder(folder_id), headers);
+ LLUUID folderId = getListingFolder(listingId);
+ setUpdating(folderId, true);
+
+ LLCoros::instance().launch("getSingleListingCoro",
+ boost::bind(&LLMarketplaceData::getSingleListingCoro, this, listingId, folderId));
+}
+
+void LLMarketplaceData::getSingleListingCoro(S32 listingId, LLUUID folderId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status.getType() == HTTP_NOT_FOUND)
+ {
+ // That listing does not exist -> delete its record from the local SLM data store
+ deleteListing(folderId, false);
+ }
+ else
+ {
+ log_SLM_warning("Get /listing", status.getType(), status.toString(), "", result);
+ }
+
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result);
+
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int resListingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Update that listing
+ setListingID(folderUuid, resListingId, false);
+ setVersionFolderID(folderUuid, versionUuid, false);
+ setActivationState(folderUuid, isListed, false);
+ setListingURL(folderUuid, editUrl, false);
+ setCountOnHand(folderUuid, count, false);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+ }
}
void LLMarketplaceData::createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Build the json message
- Json::Value root;
- Json::FastWriter writer;
-
- LLViewerInventoryCategory* category = gInventory.getCategory(folder_id);
- root["listing"]["name"] = category->getName();
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
- root["listing"]["inventory_info"]["count_on_hand"] = count;
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
-
- // Send request
- std::string url = getSLMConnectURL("/listings");
- log_SLM_infos("LLHTTPClient::postRaw", url, json_str);
- setUpdating(folder_id,true);
- LLHTTPClient::postRaw(url, data, size, new LLSLMCreateListingsResponder(folder_id), headers);
+ setUpdating(folder_id, true);
+ LLCoros::instance().launch("createSLMListingCoro",
+ boost::bind(&LLMarketplaceData::createSLMListingCoro, this, folder_id, version_id, count));
}
-void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count)
+void LLMarketplaceData::createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
- Json::Value root;
- Json::FastWriter writer;
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
- // Note : auto unlist if the count is 0 (out of stock)
- if (is_listed && (count == 0))
+ LLViewerInventoryCategory* category = gInventory.getCategory(folderId);
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ invInfo["count_on_hand"] = count;
+ LLSD listing;
+ listing["name"] = category->getName();
+ listing["inventory_info"] = invInfo;
+ LLSD postData;
+ postData["listing"] = listing;
+
+ std::string url = getSLMConnectURL("/listings");
+
+ LLSD result = httpAdapter->postJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
{
- is_listed = false;
- LLNotificationsUtil::add("AlertMerchantStockFolderEmpty");
+ log_SLM_warning("Post /listings", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
}
- // Note : we're assuming that sending unchanged info won't break anything server side...
- root["listing"]["id"] = listing_id;
- root["listing"]["is_listed"] = is_listed;
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
- root["listing"]["inventory_info"]["count_on_hand"] = count;
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
+ log_SLM_infos("Post /listings", status.getType(), result);
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+ }
+
+}
+
+void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count)
+{
+ setUpdating(folder_id, true);
+ LLCoros::instance().launch("updateSLMListingCoro",
+ boost::bind(&LLMarketplaceData::updateSLMListingCoro, this, folder_id, listing_id, version_id, is_listed, count));
+}
+
+void LLMarketplaceData::updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::putRaw", url, json_str);
- setUpdating(folder_id,true);
- LLHTTPClient::putRaw(url, data, size, new LLSLMUpdateListingsResponder(folder_id, is_listed, version_id), headers);
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ invInfo["count_on_hand"] = count;
+ LLSD listing;
+ listing["inventory_info"] = invInfo;
+ listing["id"] = listingId;
+ listing["is_listed"] = isListed;
+ LLSD postData;
+ postData["listing"] = listing;
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+ LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Put /listing", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Put /listing", status.getType(), result);
+
+ // Extract the info from the Json string
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ bool is_listed = listing["is_listed"].asBoolean();
+ std::string edit_url = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int onHand = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Update that listing
+ setListingID(folderUuid, listing_id, false);
+ setVersionFolderID(folderUuid, versionUuid, false);
+ setActivationState(folderUuid, is_listed, false);
+ setListingURL(folderUuid, edit_url, false);
+ setCountOnHand(folderUuid, onHand, false);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+
+ // Show a notification alert if what we got is not what we expected
+ // (this actually doesn't result in an error status from the SLM API protocol)
+ if ((isListed != is_listed) || (versionId != versionUuid))
+ {
+ LLSD subs;
+ subs["[URL]"] = edit_url;
+ LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs);
+ }
+ }
+
}
void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- Json::Value root;
- Json::FastWriter writer;
-
- // Note : we're assuming that sending unchanged info won't break anything server side...
- root["listing"]["id"] = listing_id;
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
-
- // Send request
- std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::putRaw", url, json_str);
- setUpdating(folder_id,true);
- setUpdating(source_folder_id,true);
- LLHTTPClient::putRaw(url, data, size, new LLSLMAssociateListingsResponder(folder_id,source_folder_id), headers);
+ setUpdating(folder_id, true);
+ setUpdating(source_folder_id, true);
+ LLCoros::instance().launch("associateSLMListingCoro",
+ boost::bind(&LLMarketplaceData::associateSLMListingCoro, this, folder_id, listing_id, version_id, source_folder_id));
}
-void LLMarketplaceData::deleteSLMListing(S32 listing_id)
+void LLMarketplaceData::associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::del", url, "");
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- setUpdating(folder_id,true);
- LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folder_id), headers);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ LLSD listing;
+ listing["id"] = listingId;
+ listing["inventory_info"] = invInfo;
+ LLSD postData;
+ postData["listing"] = listing;
+
+ // Send request
+ std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d", listingId);
+
+ LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+ setUpdating(sourceFolderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Put /associate_inventory", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ update_marketplace_category(sourceFolderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Put /associate_inventory", status.getType(), result);
+
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ bool is_listed = listing["is_listed"].asBoolean();
+ std::string edit_url = listing["edit_url"].asString();
+ LLUUID folder_uuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID version_uuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Check that the listing ID is not already associated to some other record
+ LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id);
+ if (old_listing.notNull())
+ {
+ // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID)
+ deleteListing(old_listing);
+ }
+
+ // Add the new association
+ addListing(folder_uuid, listing_id, version_uuid, is_listed, edit_url, count);
+ update_marketplace_category(folder_uuid, false);
+ gInventory.notifyObservers();
+
+ // The stock count needs to be updated with the new local count now
+ updateCountOnHand(folder_uuid, 1);
+ }
+
+ // Always update the source folder so its widget updates
+ update_marketplace_category(sourceFolderId, false);
+}
+
+void LLMarketplaceData::deleteSLMListing(S32 listingId)
+{
+ LLCoros::instance().launch("deleteSLMListingCoro",
+ boost::bind(&LLMarketplaceData::deleteSLMListingCoro, this, listingId));
+}
+
+void LLMarketplaceData::deleteSLMListingCoro(S32 listingId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+ LLUUID folderId = getListingFolder(listingId);
+
+ setUpdating(folderId, true);
+
+ LLSD result = httpAdapter->deleteJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Delete /listing", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Delete /listing", status.getType(), result);
+
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
+ deleteListing(folder_id);
+ }
+
}
std::string LLMarketplaceData::getSLMConnectURL(const std::string& route)
{
- std::string url("");
+ std::string url;
LLViewerRegion *regionp = gAgent.getRegion();
if (regionp)
{
// Get DirectDelivery cap
url = regionp->getCapability("DirectDelivery");
- if (url != "")
+ if (!url.empty())
{
url += route;
}
@@ -2133,5 +1837,3 @@ bool LLMarketplaceData::setListingURL(const LLUUID& folder_id, const std::string
return true;
}
-
-
diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h
index f8e7ed4364..9d795c6ced 100755
--- a/indra/newview/llmarketplacefunctions.h
+++ b/indra/newview/llmarketplacefunctions.h
@@ -37,8 +37,6 @@
#include "llstring.h"
-LLSD getMarketplaceStringSubstitutions();
-
namespace MarketplaceErrorCodes
{
@@ -183,6 +181,8 @@ class LLSLMDeleteListingsResponder;
class LLMarketplaceData
: public LLSingleton<LLMarketplaceData>
{
+ friend class LLSingleton < LLMarketplaceData > ;
+
public:
friend class LLSLMGetMerchantResponder;
friend class LLSLMGetListingsResponder;
@@ -192,9 +192,8 @@ public:
friend class LLSLMAssociateListingsResponder;
friend class LLSLMDeleteListingsResponder;
- LLMarketplaceData();
- virtual ~LLMarketplaceData();
-
+ static LLSD getMarketplaceStringSubstitutions();
+
// Public SLM API : Initialization and status
typedef boost::signals2::signal<void ()> status_updated_signal_t;
void initializeSLM(const status_updated_signal_t::slot_type& cb);
@@ -241,8 +240,11 @@ public:
// Used to decide when to run a validation on listing folders
void setValidationWaiting(const LLUUID& folder_id, S32 count);
void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1);
-
+
private:
+ LLMarketplaceData();
+ virtual ~LLMarketplaceData();
+
// Modify Marketplace data set : each method returns true if the function succeeds, false if error
// Used internally only by SLM Responders when data are received from the SLM Server
bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count);
@@ -261,6 +263,14 @@ private:
void deleteSLMListing(S32 listing_id);
std::string getSLMConnectURL(const std::string& route);
+ void getMerchantStatusCoro();
+ void getSLMListingsCoro(LLUUID folderId);
+ void getSingleListingCoro(S32 listingId, LLUUID folderId);
+ void createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count);
+ void updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count);
+ void associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId);
+ void deleteSLMListingCoro(S32 listingId);
+
// Handling Marketplace connection and inventory connection
U32 mMarketPlaceStatus;
status_updated_signal_t* mStatusUpdatedSignal;
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index 1045def72e..9ac560c217 100755
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -579,46 +579,59 @@ void LLMaterialMgr::onIdle(void*)
instancep->mHttpRequest->update(0L);
}
-void LLMaterialMgr::processGetQueue()
+/*static*/
+void LLMaterialMgr::CapsRecvForRegion(const LLUUID& regionId, LLUUID regionTest, std::string pumpname)
{
- 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;
- }
+ if (regionId == regionTest)
+ {
+ LLEventPumps::instance().obtain(pumpname).post(LLSD());
+ }
+}
+void LLMaterialMgr::processGetQueue()
+{
+ get_queue_t::iterator loopRegionQueue = mGetQueue.begin();
+ while (mGetQueue.end() != loopRegionQueue)
+ {
+#if 1
+ //* $TODO: This block is screaming to be turned into a coroutine.
+ // see processGetQueueCoro() below.
+ //
+ 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;
@@ -652,10 +665,9 @@ void LLMaterialMgr::processGetQueue()
LLSD postData = LLSD::emptyMap();
postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
- LLMaterialHttpHandler * handler =
- new LLMaterialHttpHandler("POST",
+ LLCore::HttpHandler::ptr_t handler(new LLMaterialHttpHandler("POST",
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;
@@ -666,7 +678,6 @@ void LLMaterialMgr::processGetQueue()
if (handle == LLCORE_HTTP_HANDLE_INVALID)
{
- delete handler;
LLCore::HttpStatus status = mHttpRequest->getStatus();
LL_ERRS("Meterials") << "Failed to execute material POST. Status = " <<
status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
@@ -674,6 +685,103 @@ void LLMaterialMgr::processGetQueue()
regionp->resetMaterialsCapThrottle();
}
+#endif
+}
+
+void LLMaterialMgr::processGetQueueCoro()
+{
+#if 0
+ 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() < 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;
+
+ LLMaterialHttpHandler * handler =
+ new LLMaterialHttpHandler("POST",
+ 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;
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicy, mHttpPriority, capURL,
+ postData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material POST. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
+ regionp->resetMaterialsCapThrottle();
+#endif
+
}
void LLMaterialMgr::processGetAllQueue()
@@ -684,50 +792,87 @@ void LLMaterialMgr::processGetAllQueue()
getall_queue_t::iterator itRegion = loopRegion++;
const LLUUID& region_id = *itRegion;
- LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
- if (regionp == NULL)
- {
- LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
- clearGetQueues(region_id); // Invalidates region_id
- continue;
- }
- else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
- {
- continue;
- }
- std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
- if (capURL.empty())
- {
- LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
- << "' is not defined on the current region '" << regionp->getName() << "'" << LL_ENDL;
- clearGetQueues(region_id); // Invalidates region_id
- continue;
- }
-
- LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
- LLMaterialHttpHandler *handler =
- new LLMaterialHttpHandler("GET",
- boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)
- );
-
- LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL,
- mHttpOptions, mHttpHeaders, handler);
-
- if (handle == LLCORE_HTTP_HANDLE_INVALID)
- {
- delete handler;
- LLCore::HttpStatus status = mHttpRequest->getStatus();
- LL_ERRS("Meterials") << "Failed to execute material GET. Status = " <<
- status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
- }
+ LLCoros::instance().launch("LLMaterialMgr::processGetAllQueueCoro", boost::bind(&LLMaterialMgr::processGetAllQueueCoro,
+ this, region_id));
- regionp->resetMaterialsCapThrottle();
- mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
+ mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
mGetAllQueue.erase(itRegion); // Invalidates region_id
}
}
+void LLMaterialMgr::processGetAllQueueCoro(LLUUID regionId)
+{
+ LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(regionId);
+ if (regionp == NULL)
+ {
+ LL_WARNS("Materials") << "Unknown region with id " << regionId.asString() << LL_ENDL;
+ clearGetQueues(regionId); // Invalidates region_id
+ return;
+ }
+ else if (!regionp->capabilitiesReceived())
+ {
+ LLEventStream capsRecv("waitForCaps", true);
+
+ regionp->setCapabilitiesReceivedCallback(
+ boost::bind(&LLMaterialMgr::CapsRecvForRegion,
+ _1, regionId, capsRecv.getName()));
+
+ llcoro::suspendUntilEventOn(capsRecv);
+
+ // reget the region from the region ID since it may have gone away while waiting.
+ regionp = LLWorld::instance().getRegionFromID(regionId);
+ if (!regionp)
+ {
+ LL_WARNS("Materials") << "Region with ID " << regionId << " is no longer valid." << LL_ENDL;
+ return;
+ }
+ }
+ else if (regionp->materialsCapThrottled())
+ {
+ // TODO:
+ // Figure out how to handle the throttle.
+ }
+
+ std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
+ if (capURL.empty())
+ {
+ LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
+ << "' is not defined on the current region '" << regionp->getName() << "'" << LL_ENDL;
+ clearGetQueues(regionId); // Invalidates region_id
+ return;
+ }
+
+ LL_DEBUGS("Materials") << "GET all for region " << regionId << "url " << capURL << LL_ENDL;
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(
+ new LLCoreHttpUtil::HttpCoroutineAdapter("processGetAllQueue", LLCore::HttpRequest::DEFAULT_POLICY_ID));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, capURL);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ onGetAllResponse(false, LLSD(), regionId);
+ }
+ else
+ {
+ onGetAllResponse(true, result, regionId);
+ }
+
+ // reget the region from the region ID since it may have gone away while waiting.
+ regionp = LLWorld::instance().getRegionFromID(regionId);
+ if (!regionp)
+ {
+ LL_WARNS("Materials") << "Region with ID " << regionId << " is no longer valid." << LL_ENDL;
+ return;
+ }
+ regionp->resetMaterialsCapThrottle();
+}
+
void LLMaterialMgr::processPutQueue()
{
typedef std::map<LLViewerRegion*, LLSD> regionput_request_map;
@@ -749,34 +894,34 @@ void LLMaterialMgr::processPutQueue()
{
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() < 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);
- }
- }
+ 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() < 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);
+ }
+ }
}
}
@@ -809,10 +954,9 @@ void LLMaterialMgr::processPutQueue()
LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
- LLMaterialHttpHandler * handler =
- new LLMaterialHttpHandler("PUT",
- boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)
- );
+ LLCore::HttpHandler::ptr_t handler (new LLMaterialHttpHandler("PUT",
+ boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)
+ ));
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD(
mHttpRequest, mHttpPolicy, mHttpPriority, capURL,
@@ -820,7 +964,6 @@ void LLMaterialMgr::processPutQueue()
if (handle == LLCORE_HTTP_HANDLE_INVALID)
{
- delete handler;
LLCore::HttpStatus status = mHttpRequest->getStatus();
LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " <<
status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
@@ -838,6 +981,7 @@ void LLMaterialMgr::processPutQueue()
void LLMaterialMgr::clearGetQueues(const LLUUID& region_id)
{
mGetQueue.erase(region_id);
+
for (get_pending_map_t::iterator itPending = mGetPending.begin(); itPending != mGetPending.end();)
{
if (region_id == itPending->first.first)
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index ef202d24ba..36dd0904b6 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -67,9 +67,14 @@ private:
const LLMaterialPtr setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data);
static void onIdle(void*);
+
+ static void CapsRecvForRegion(const LLUUID& regionId, LLUUID regionTest, std::string pumpname);
+
void processGetQueue();
+ void processGetQueueCoro();
void onGetResponse(bool success, const LLSD& content, const LLUUID& region_id);
void processGetAllQueue();
+ void processGetAllQueueCoro(LLUUID regionId);
void onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id);
void processPutQueue();
void onPutResponse(bool success, const LLSD& content);
@@ -116,7 +121,9 @@ private:
typedef std::map<U8, LLMaterial> facematerial_map_t;
typedef std::map<LLUUID, facematerial_map_t> put_queue_t;
+
get_queue_t mGetQueue;
+ uuid_set_t mRegionGets;
get_pending_map_t mGetPending;
get_callback_map_t mGetCallbacks;
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index b96bdd73ff..73faed7ef5 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -95,6 +95,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mStretchToFill( true ),
mMaintainAspectRatio ( true ),
mDecoupleTextureSize ( false ),
+ mUpdateScrolls( false ),
mTextureWidth ( 1024 ),
mTextureHeight ( 1024 ),
mClearCache(false),
@@ -682,7 +683,13 @@ bool LLMediaCtrl::ensureMediaSourceExists()
mMediaSource->addObserver( this );
mMediaSource->setBackgroundColor( getBackgroundColor() );
mMediaSource->setTrustedBrowser(mTrusted);
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
if(mClearCache)
{
@@ -720,10 +727,11 @@ void LLMediaCtrl::draw()
{
F32 alpha = getDrawContext().mAlpha;
- if ( gRestoreGL == 1 )
+ if ( gRestoreGL == 1 || mUpdateScrolls)
{
LLRect r = getRect();
reshape( r.getWidth(), r.getHeight(), FALSE );
+ mUpdateScrolls = false;
return;
}
@@ -765,7 +773,12 @@ void LLMediaCtrl::draw()
{
gGL.pushUIMatrix();
{
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
// scale texture to fit the space using texture coords
gGL.getTexUnit(0)->bind(media_texture);
@@ -970,11 +983,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
case MEDIA_EVENT_CLICK_LINK_HREF:
{
- LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
// retrieve the event parameters
std::string url = self->getClickURL();
- std::string target = self->getClickTarget();
+ std::string target = self->isOverrideClickTarget() ? self->getOverrideClickTarget() : self->getClickTarget();
std::string uuid = self->getClickUUID();
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL;
LLNotification::Params notify_params;
notify_params.name = "PopupAttempt";
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 785c57b78a..988733b85a 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -192,7 +192,8 @@ public:
mHidingInitialLoad,
mClearCache,
mHoverTextChanged,
- mDecoupleTextureSize;
+ mDecoupleTextureSize,
+ mUpdateScrolls;
std::string mHomePageUrl,
mHomePageMimeType,
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index b8ff76aa6d..bd8f464acd 100755
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -353,14 +353,12 @@ void LLMediaDataClient::serviceQueue()
trackRequest(request);
// and make the post
- LLHttpSDHandler *handler = request->createHandler();
+ LLCore::HttpHandler::ptr_t handler = request->createHandler();
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, 0,
url, sd_payload, mHttpOpts, mHttpHeaders, handler);
if (handle == LLCORE_HTTP_HANDLE_INVALID)
{
- // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers. Requires change in LLCore::HTTP
- delete handler;
LLCore::HttpStatus status = mHttpRequest->getStatus();
LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason "
<< status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL;
@@ -631,14 +629,8 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo
if (status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE))
{
F32 retry_timeout;
-#if 0
- // *TODO: Honor server Retry-After header.
- if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER)
- || !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout))
-#endif
- {
- retry_timeout = mRequest->getRetryTimerDelay();
- }
+
+ retry_timeout = mRequest->getRetryTimerDelay();
mRequest->incRetryCount();
@@ -884,9 +876,9 @@ LLSD LLObjectMediaDataClient::RequestGet::getPayload() const
return result;
}
-LLHttpSDHandler *LLObjectMediaDataClient::RequestGet::createHandler()
+LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestGet::createHandler()
{
- return new LLObjectMediaDataClient::Handler(shared_from_this());
+ return LLCore::HttpHandler::ptr_t(new LLObjectMediaDataClient::Handler(shared_from_this()));
}
@@ -920,10 +912,10 @@ LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const
return result;
}
-LLHttpSDHandler *LLObjectMediaDataClient::RequestUpdate::createHandler()
+LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestUpdate::createHandler()
{
// This just uses the base class's responder.
- return new LLMediaDataClient::Handler(shared_from_this());
+ return LLCore::HttpHandler::ptr_t(new LLMediaDataClient::Handler(shared_from_this()));
}
void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
@@ -1055,9 +1047,9 @@ LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const
return result;
}
-LLHttpSDHandler *LLObjectMediaNavigateClient::RequestNavigate::createHandler()
+LLCore::HttpHandler::ptr_t LLObjectMediaNavigateClient::RequestNavigate::createHandler()
{
- return new LLObjectMediaNavigateClient::Handler(shared_from_this());
+ return LLCore::HttpHandler::ptr_t(new LLObjectMediaNavigateClient::Handler(shared_from_this()));
}
void LLObjectMediaNavigateClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 9907897613..58f8bad3e4 100755
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -124,7 +124,7 @@ protected:
// Subclasses must implement this to build a payload for their request type.
virtual LLSD getPayload() const = 0;
// and must create the correct type of responder.
- virtual LLHttpSDHandler *createHandler() = 0;
+ virtual LLCore::HttpHandler::ptr_t createHandler() = 0;
virtual std::string getURL() { return ""; }
@@ -324,7 +324,7 @@ public:
public:
RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ LLHttpSDHandler *createHandler();
+ /*virtual*/ LLCore::HttpHandler::ptr_t createHandler();
};
class RequestUpdate: public Request
@@ -332,7 +332,7 @@ public:
public:
RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ LLHttpSDHandler *createHandler();
+ /*virtual*/ LLCore::HttpHandler::ptr_t createHandler();
};
// Returns true iff the queue is empty
@@ -409,7 +409,7 @@ public:
public:
RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ LLHttpSDHandler *createHandler();
+ /*virtual*/ LLCore::HttpHandler::ptr_t createHandler();
/*virtual*/ std::string getURL() { return mURL; }
private:
std::string mURL;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 5bd9df54e2..e42367ad9e 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file llmeshrepository.cpp
* @brief Mesh repository implementation.
*
@@ -36,7 +36,6 @@
#include "llappviewer.h"
#include "llbufferstream.h"
#include "llcallbacklist.h"
-#include "llcurl.h"
#include "lldatapacker.h"
#include "lldeadmantimer.h"
#include "llfloatermodelpreview.h"
@@ -393,6 +392,19 @@ U32 LLMeshRepository::sMaxLockHoldoffs = 0;
LLDeadmanTimer LLMeshRepository::sQuiescentTimer(15.0, false); // true -> gather cpu metrics
+namespace {
+ // The NoOpDeletor is used when passing certain objects (generally the LLMeshUploadThread)
+ // in a smart pointer below for passage into the LLCore::Http libararies.
+ // When the smart pointer is destroyed, no action will be taken since we
+ // do not in these cases want the object to be destroyed at the end of the call.
+ //
+ // *NOTE$: Yes! It is "Deletor"
+ // http://english.stackexchange.com/questions/4733/what-s-the-rule-for-adding-er-vs-or-when-nouning-a-verb
+ // "delete" derives from Latin "deletus"
+
+ void NoOpDeletor(LLCore::HttpHandler *)
+ { /*NoOp*/ }
+}
static S32 dump_num = 0;
std::string make_dump_name(std::string prefix, S32 num)
@@ -508,6 +520,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res,
}
}
+LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
+{
+ LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
+ return ppTex ? (*ppTex).get() : NULL;
+}
+
volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
@@ -533,9 +551,12 @@ S32 LLMeshRepoThread::sRequestWaterLevel = 0;
// LLMeshPhysicsShapeHandler
// LLMeshUploadThread
-class LLMeshHandlerBase : public LLCore::HttpHandler
+class LLMeshHandlerBase : public LLCore::HttpHandler,
+ public boost::enable_shared_from_this<LLMeshHandlerBase>
{
public:
+ typedef boost::shared_ptr<LLMeshHandlerBase> ptr_t;
+
LOG_CLASS(LLMeshHandlerBase);
LLMeshHandlerBase(U32 offset, U32 requested_bytes)
: LLCore::HttpHandler(),
@@ -602,16 +623,16 @@ public:
LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)
: LLMeshHandlerBase(offset, requested_bytes),
mLOD(lod)
- {
+ {
mMeshParams = mesh_params;
LLMeshRepoThread::incActiveLODRequests();
}
virtual ~LLMeshLODHandler();
-
+
protected:
LLMeshLODHandler(const LLMeshLODHandler &); // Not defined
void operator=(const LLMeshLODHandler &); // Not defined
-
+
public:
virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
@@ -811,7 +832,7 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
}
-
+
LLMeshRepoThread::~LLMeshRepoThread()
{
LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount
@@ -819,12 +840,6 @@ LLMeshRepoThread::~LLMeshRepoThread()
<< ", Max Lock Holdoffs: " << LLMeshRepository::sMaxLockHoldoffs
<< LL_ENDL;
- for (http_request_set::iterator iter(mHttpRequestSet.begin());
- iter != mHttpRequestSet.end();
- ++iter)
- {
- delete *iter;
- }
mHttpRequestSet.clear();
mHttpHeaders.reset();
@@ -867,16 +882,16 @@ void LLMeshRepoThread::run()
{
break;
}
-
+
if (! mHttpRequestSet.empty())
{
// Dispatch all HttpHandler notifications
mHttpRequest->update(0L);
}
sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update
-
- // NOTE: order of queue processing intentionally favors LOD requests over header requests
+ // NOTE: order of queue processing intentionally favors LOD requests over header requests
+
while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
{
if (! mMutex)
@@ -940,7 +955,7 @@ void LLMeshRepoThread::run()
mSkinRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshSkinInfo(mesh_id))
+ if (! fetchMeshSkinInfo(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -969,7 +984,7 @@ void LLMeshRepoThread::run()
mDecompositionRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshDecomposition(mesh_id))
+ if (! fetchMeshDecomposition(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -995,7 +1010,7 @@ void LLMeshRepoThread::run()
mPhysicsShapeRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshPhysicsShape(mesh_id))
+ if (! fetchMeshPhysicsShape(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -1156,7 +1171,7 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * ver
// Thread: repo
LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int cap_version,
size_t offset, size_t len,
- LLCore::HttpHandler * handler)
+ const LLCore::HttpHandler::ptr_t &handler)
{
// Also used in lltexturefetch.cpp
static LLCachedControl<bool> disable_range_req(gSavedSettings, "HttpRangeRequestsDisable", false);
@@ -1221,7 +1236,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
}
++LLMeshRepository::sMeshRequestCount;
- bool ret = true ;
+ bool ret = true;
U32 header_size = mMeshHeaderSize[mesh_id];
if (header_size > 0)
@@ -1269,8 +1284,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
constructUrl(mesh_id, &http_url, &cap_version);
if (!http_url.empty())
- {
- LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);
+ {
+ LLMeshHandlerBase::ptr_t handler(new LLMeshSkinInfoHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1278,7 +1293,6 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
<< ". Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- delete handler;
ret = false;
}
else
@@ -1315,7 +1329,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
++LLMeshRepository::sMeshRequestCount;
U32 header_size = mMeshHeaderSize[mesh_id];
- bool ret = true ;
+ bool ret = true;
if (header_size > 0)
{
@@ -1361,10 +1375,10 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
- LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);
+ {
+ LLMeshHandlerBase::ptr_t handler(new LLMeshDecompositionHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1372,7 +1386,6 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
<< ". Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- delete handler;
ret = false;
}
else
@@ -1409,7 +1422,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
++LLMeshRepository::sMeshRequestCount;
U32 header_size = mMeshHeaderSize[mesh_id];
- bool ret = true ;
+ bool ret = true;
if (header_size > 0)
{
@@ -1454,10 +1467,10 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
- LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);
+ {
+ LLMeshHandlerBase::ptr_t handler(new LLMeshPhysicsShapeHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1465,7 +1478,6 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
<< ". Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- delete handler;
ret = false;
}
else
@@ -1545,18 +1557,18 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
}
//either cache entry doesn't exist or is corrupt, request header from simulator
- bool retval = true ;
+ bool retval = true;
int cap_version(2);
std::string http_url;
constructUrl(mesh_params.getSculptID(), &http_url, &cap_version);
-
+
if (!http_url.empty())
{
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
//within the first 4KB
//NOTE -- this will break of headers ever exceed 4KB
- LLMeshHeaderHandler * handler = new LLMeshHeaderHandler(mesh_params, 0, MESH_HEADER_SIZE);
+ LLMeshHandlerBase::ptr_t handler(new LLMeshHeaderHandler(mesh_params, 0, MESH_HEADER_SIZE));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1564,7 +1576,6 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
<< ". Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- delete handler;
retval = false;
}
else
@@ -1637,10 +1648,10 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
- LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);
+ {
+ LLMeshHandlerBase::ptr_t handler(new LLMeshLODHandler(mesh_params, lod, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1648,7 +1659,6 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
<< ". Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- delete handler;
retval = false;
}
else
@@ -1911,7 +1921,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mOrigin += gAgent.getAtAxis() * scale.magVec();
- mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ;
+ mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");
mHttpRequest = new LLCore::HttpRequest;
mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
@@ -1969,14 +1979,14 @@ void LLMeshUploadThread::preStart()
void LLMeshUploadThread::discard()
{
- LLMutexLock lock(mMutex) ;
+ LLMutexLock lock(mMutex);
mDiscarded = true;
}
bool LLMeshUploadThread::isDiscarded() const
{
- LLMutexLock lock(mMutex) ;
- return mDiscarded ;
+ LLMutexLock lock(mMutex);
+ return mDiscarded;
}
void LLMeshUploadThread::run()
@@ -2041,6 +2051,14 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
{
LLMeshUploadData data;
data.mBaseModel = iter->first;
+
+ if (data.mBaseModel->mSubmodelID)
+ {
+ // These are handled below to insure correct parenting order on creation
+ // due to map walking being based on model address (aka random)
+ continue;
+ }
+
LLModelInstance& first_instance = *(iter->second.begin());
for (S32 i = 0; i < 5; i++)
{
@@ -2078,7 +2096,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
data.mModel[LLModel::LOD_IMPOSTOR],
decomp,
mUploadSkin,
- mUploadJoints);
+ mUploadJoints,
+ FALSE,
+ FALSE,
+ data.mBaseModel->mSubmodelID);
data.mAssetData = ostr.str();
std::string str = ostr.str();
@@ -2112,17 +2133,26 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
instance_entry["scale"] = ll_sd_from_vector3(scale);
instance_entry["material"] = LL_MCODE_WOOD;
- instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+ instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
instance_entry["mesh"] = mesh_index[data.mBaseModel];
instance_entry["face_list"] = LLSD::emptyArray();
- S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
+ // We want to be able to allow more than 8 materials...
+ //
+ S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
+
for (S32 face_num = 0; face_num < end; face_num++)
{
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
LLSD face_entry = LLSD::emptyMap();
- LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
+
+ LLViewerFetchedTexture *texture = NULL;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ texture = FindViewerTexture(material);
+ }
if ((texture != NULL) &&
(textures.find(texture) == textures.end()))
@@ -2137,9 +2167,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
{
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
+
+ if (!upload_file.isNull() && upload_file->getDataSize())
+ {
+ texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
+ }
+ }
+ }
+
+ if (texture != NULL &&
+ mUploadTextures &&
+ texture_index.find(texture) == texture_index.end())
+ {
+ texture_index[texture] = texture_num;
+ std::string str = texture_str.str();
+ res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
+ texture_num++;
+ }
+
+ // Subset of TextureEntry fields.
+ if (texture != NULL && mUploadTextures)
+ {
+ face_entry["image"] = texture_index[texture];
+ face_entry["scales"] = 1.0;
+ face_entry["scalet"] = 1.0;
+ face_entry["offsets"] = 0.0;
+ face_entry["offsett"] = 0.0;
+ face_entry["imagerot"] = 0.0;
+ }
+ face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
+ face_entry["fullbright"] = material.mFullbright;
+ instance_entry["face_list"][face_num] = face_entry;
+ }
+
+ res["instance_list"][instance_num] = instance_entry;
+ instance_num++;
+ }
+ }
+
+ for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
+ {
+ LLMeshUploadData data;
+ data.mBaseModel = iter->first;
+
+ if (!data.mBaseModel->mSubmodelID)
+ {
+ // These were handled above already...
+ //
+ continue;
+ }
+
+ LLModelInstance& first_instance = *(iter->second.begin());
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = first_instance.mLOD[i];
+ }
+
+ if (mesh_index.find(data.mBaseModel) == mesh_index.end())
+ {
+ // Have not seen this model before - create a new mesh_list entry for it.
+ if (model_name.empty())
+ {
+ model_name = data.mBaseModel->getName();
+ }
+
+ if (model_metric.empty())
+ {
+ model_metric = data.mBaseModel->getMetric();
+ }
+
+ std::stringstream ostr;
+
+ LLModel::Decomposition& decomp =
+ data.mModel[LLModel::LOD_PHYSICS].notNull() ?
+ data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
+ data.mBaseModel->mPhysics;
+
+ decomp.mBaseHull = mHullMap[data.mBaseModel];
+
+ LLSD mesh_header = LLModel::writeModel(
+ ostr,
+ data.mModel[LLModel::LOD_PHYSICS],
+ data.mModel[LLModel::LOD_HIGH],
+ data.mModel[LLModel::LOD_MEDIUM],
+ data.mModel[LLModel::LOD_LOW],
+ data.mModel[LLModel::LOD_IMPOSTOR],
+ decomp,
+ mUploadSkin,
+ mUploadJoints,
+ FALSE,
+ FALSE,
+ data.mBaseModel->mSubmodelID);
+
+ data.mAssetData = ostr.str();
+ std::string str = ostr.str();
+
+ res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());
+ mesh_index[data.mBaseModel] = mesh_num;
+ mesh_num++;
+ }
+
+ // For all instances that use this model
+ for (instance_list::iterator instance_iter = iter->second.begin();
+ instance_iter != iter->second.end();
+ ++instance_iter)
+ {
+
+ LLModelInstance& instance = *instance_iter;
+
+ LLSD instance_entry;
+
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = instance.mLOD[i];
+ }
+
+ LLVector3 pos, scale;
+ LLQuaternion rot;
+ LLMatrix4 transformation = instance.mTransform;
+ decomposeMeshMatrix(transformation,pos,rot,scale);
+ instance_entry["position"] = ll_sd_from_vector3(pos);
+ instance_entry["rotation"] = ll_sd_from_quaternion(rot);
+ instance_entry["scale"] = ll_sd_from_vector3(scale);
+
+ instance_entry["material"] = LL_MCODE_WOOD;
+ instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE);
+ instance_entry["mesh"] = mesh_index[data.mBaseModel];
+
+ instance_entry["face_list"] = LLSD::emptyArray();
+
+ // We want to be able to allow more than 8 materials...
+ //
+ S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
+
+ for (S32 face_num = 0; face_num < end; face_num++)
+ {
+ LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
+ LLSD face_entry = LLSD::emptyMap();
+
+ LLViewerFetchedTexture *texture = NULL;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ texture = FindViewerTexture(material);
+ }
+
+ if ((texture != NULL) &&
+ (textures.find(texture) == textures.end()))
+ {
+ textures.insert(texture);
+ }
+
+ std::stringstream texture_str;
+ if (texture != NULL && include_textures && mUploadTextures)
+ {
+ if(texture->hasSavedRawImage())
+ {
+ LLPointer<LLImageJ2C> upload_file =
+ LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
+
+ if (!upload_file.isNull() && upload_file->getDataSize())
+ {
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
}
+ }
if (texture != NULL &&
mUploadTextures &&
@@ -2227,7 +2419,7 @@ void LLMeshUploadThread::generateHulls()
}
}
- if(has_valid_requests)
+ if (has_valid_requests)
{
// *NOTE: Interesting livelock condition on shutdown. If there
// is an upload request in generateHulls() when shutdown starts,
@@ -2269,7 +2461,7 @@ void LLMeshUploadThread::doWholeModelUpload()
body,
mHttpOptions,
mHttpHeaders,
- this);
+ LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
mHttpStatus = mHttpRequest->getStatus();
@@ -2320,7 +2512,7 @@ void LLMeshUploadThread::requestWholeModelFee()
mModelData,
mHttpOptions,
mHttpHeaders,
- this);
+ LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
mHttpStatus = mHttpRequest->getStatus();
@@ -2332,7 +2524,7 @@ void LLMeshUploadThread::requestWholeModelFee()
else
{
U32 sleep_time(10);
-
+
mHttpRequest->update(0);
while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())
{
@@ -2427,7 +2619,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
// model fee case
LLWholeModelFeeObserver* observer(mFeeObserverHandle.get());
mWholeModelUploadURL.clear();
-
+
if (! status)
{
LL_WARNS(LOG_MESH) << "Fee request failed. Reason: " << reason
@@ -2457,7 +2649,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
LLCoreHttpUtil::responseToLLSD(response, true, body);
}
dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num));
-
+
if (body["state"].asString() == "upload")
{
mWholeModelUploadURL = body["uploader"].asString();
@@ -2528,7 +2720,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
LODRequest req = mUnavailableQ.front();
mUnavailableQ.pop();
mMutex->unlock();
-
+
update_metrics = true;
gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
}
@@ -2664,7 +2856,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
{
mProcessed = true;
-
+
unsigned int retries(0U);
response->getRetries(NULL, &retries);
LLMeshRepository::sHTTPRetryCount += retries;
@@ -2720,7 +2912,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
// 200 case, typically
offset = 0;
}
-
+
// *DEBUG: To test validation below
// offset += 1;
@@ -2761,8 +2953,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
// Release handler
common_exit:
- gMeshRepo.mThread->mHttpRequestSet.erase(this);
- delete this; // Must be last statement
+ gMeshRepo.mThread->mHttpRequestSet.erase(this->shared_from_this());
}
@@ -2836,7 +3027,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
const std::string & lod_name = header_lod[i];
lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
}
-
+
// just in case skin info or decomposition is at the end of the file (which it shouldn't be)
lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
@@ -2844,7 +3035,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
S32 bytes = lod_bytes + header_bytes;
-
+
// It's possible for the remote asset to have more data than is needed for the local cache
// only allocate as much space in the VFS as is needed for the local cache
data_size = llmin(data_size, bytes);
@@ -2856,11 +3047,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
++LLMeshRepository::sCacheWrites;
file.write(data, data_size);
-
+
// zero out the rest of the file
U8 block[MESH_HEADER_SIZE];
memset(block, 0, sizeof(block));
-
+
while (bytes-file.tell() > sizeof(block))
{
file.write(block, sizeof(block));
@@ -2886,8 +3077,8 @@ LLMeshLODHandler::~LLMeshLODHandler()
gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);
}
LLMeshRepoThread::decActiveLODRequests();
- }
}
+}
void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
{
@@ -2905,7 +3096,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
{
if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
{
- //good fetch from sim, write to VFS for caching
+ // good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
S32 offset = mOffset;
@@ -2950,7 +3141,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*
{
if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
{
- //good fetch from sim, write to VFS for caching
+ // good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
S32 offset = mOffset;
@@ -3274,7 +3465,7 @@ void LLMeshRepository::notifyLoadedMeshes()
REQUEST2_LOW_WATER_MIN,
REQUEST2_LOW_WATER_MAX);
}
-
+
//clean up completed upload threads
for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
{
@@ -3351,7 +3542,7 @@ void LLMeshRepository::notifyLoadedMeshes()
//call completed callbacks on finished decompositions
mDecompThread->notifyCompleted();
-
+
// For major operations, attempt to get the required locks
// without blocking and punt if they're not available. The
// longest run of holdoffs is kept in sMaxLockHoldoffs just
@@ -3370,12 +3561,12 @@ void LLMeshRepository::notifyLoadedMeshes()
return;
}
hold_offs = 0;
-
+
if (gAgent.getRegion())
{
// Update capability urls
static std::string region_name("never name a region this");
-
+
if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
{
region_name = gAgent.getRegion()->getName();
@@ -3391,7 +3582,7 @@ void LLMeshRepository::notifyLoadedMeshes()
<< LL_ENDL;
}
}
-
+
//popup queued error messages from background threads
while (!mUploadErrorQ.empty())
{
@@ -3746,7 +3937,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
- bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
+ bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
{
LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url,
@@ -3817,37 +4008,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
result_rot = quat_rotation;
}
-bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
-{
- if (mDiffuseMap != rhs.mDiffuseMap)
- {
- return mDiffuseMap < rhs.mDiffuseMap;
- }
-
- if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
- {
- return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
- }
-
- if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
- {
- return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
- }
-
- if (mDiffuseColor != rhs.mDiffuseColor)
- {
- return mDiffuseColor < rhs.mDiffuseColor;
- }
-
- if (mBinding != rhs.mBinding)
- {
- return mBinding < rhs.mBinding;
- }
-
- return mFullbright < rhs.mFullbright;
-}
-
-
void LLMeshRepository::updateInventory(inventory_data data)
{
LLMutexLock lock(mMeshMutex);
@@ -4245,7 +4405,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
setMeshData(mesh, true);
LLCDResult ret = decomp->buildSingleHull() ;
- if(ret)
+ if (ret)
{
LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
make_box(mCurRequest);
@@ -4433,60 +4593,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)
mStatusMessage = msg;
}
-LLModelInstance::LLModelInstance(LLSD& data)
-{
- mLocalMeshID = data["mesh_id"].asInteger();
- mLabel = data["label"].asString();
- mTransform.setValue(data["transform"]);
-
- for (U32 i = 0; i < data["material"].size(); ++i)
- {
- LLImportMaterial mat(data["material"][i]);
- mMaterial[mat.mBinding] = mat;
- }
-}
-
-
-LLSD LLModelInstance::asLLSD()
-{
- LLSD ret;
-
- ret["mesh_id"] = mModel->mLocalID;
- ret["label"] = mLabel;
- ret["transform"] = mTransform.getValue();
-
- U32 i = 0;
- for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
- {
- ret["material"][i++] = iter->second.asLLSD();
- }
-
- return ret;
-}
-
-LLImportMaterial::LLImportMaterial(LLSD& data)
-{
- mDiffuseMapFilename = data["diffuse"]["filename"].asString();
- mDiffuseMapLabel = data["diffuse"]["label"].asString();
- mDiffuseColor.setValue(data["diffuse"]["color"]);
- mFullbright = data["fullbright"].asBoolean();
- mBinding = data["binding"].asString();
-}
-
-
-LLSD LLImportMaterial::asLLSD()
-{
- LLSD ret;
-
- ret["diffuse"]["filename"] = mDiffuseMapFilename;
- ret["diffuse"]["label"] = mDiffuseMapLabel;
- ret["diffuse"]["color"] = mDiffuseColor.getValue();
- ret["fullbright"] = mFullbright;
- ret["binding"] = mBinding;
-
- return ret;
-}
-
void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
{
decomp.mMesh.resize(decomp.mHull.size());
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 55157cc040..d35c44397b 100755
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -38,6 +38,7 @@
#include "httpoptions.h"
#include "httpheaders.h"
#include "httphandler.h"
+#include "llthread.h"
#define LLCONVEXDECOMPINTER_STATIC 1
@@ -90,54 +91,6 @@ public:
}
};
-class LLImportMaterial
-{
-public:
- LLPointer<LLViewerFetchedTexture> mDiffuseMap;
- std::string mDiffuseMapFilename;
- std::string mDiffuseMapLabel;
- std::string mBinding;
- LLColor4 mDiffuseColor;
- bool mFullbright;
-
- bool operator<(const LLImportMaterial &params) const;
-
- LLImportMaterial()
- : mFullbright(false)
- {
- mDiffuseColor.set(1,1,1,1);
- }
-
- LLImportMaterial(LLSD& data);
-
- LLSD asLLSD();
-};
-
-class LLModelInstance
-{
-public:
- LLPointer<LLModel> mModel;
- LLPointer<LLModel> mLOD[5];
-
- std::string mLabel;
-
- LLUUID mMeshID;
- S32 mLocalMeshID;
-
- LLMatrix4 mTransform;
- std::map<std::string, LLImportMaterial> mMaterial;
-
- LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
- : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
- {
- mLocalMeshID = -1;
- }
-
- LLModelInstance(LLSD& data);
-
- LLSD asLLSD();
-};
-
class LLPhysicsDecomp : public LLThread
{
public:
@@ -330,7 +283,7 @@ public:
LLCore::HttpRequest::policy_t mHttpLargePolicyClass;
LLCore::HttpRequest::priority_t mHttpPriority;
- typedef std::set<LLCore::HttpHandler *> http_request_set;
+ typedef std::set<LLCore::HttpHandler::ptr_t> http_request_set;
http_request_set mHttpRequestSet; // Outstanding HTTP requests
std::string mGetMeshCapability;
@@ -398,7 +351,7 @@ private:
// Threads: Repo thread only
LLCore::HttpHandle getByteRange(const std::string & url, int cap_version,
size_t offset, size_t len,
- LLCore::HttpHandler * handler);
+ const LLCore::HttpHandler::ptr_t &handler);
};
@@ -483,6 +436,8 @@ public:
// Inherited from LLCore::HttpHandler
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+ LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material);
+
private:
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index fe562baf96..70035bcc74 100755
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -303,7 +303,15 @@ void LLFloaterMove::onFlyButtonClick()
void LLFloaterMove::setMovementMode(const EMovementMode mode)
{
mCurrentMode = mode;
- gAgent.setFlying(MM_FLY == mode);
+
+ if(MM_FLY == mode)
+ {
+ LLAgent::toggleFlying();
+ }
+ else
+ {
+ gAgent.setFlying(FALSE);
+ }
// attempts to set avatar flying can not set it real flying in some cases.
// For ex. when avatar fell down & is standing up.
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 79988a0800..5510598ae7 100755
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -130,8 +130,14 @@ BOOL LLNameListCtrl::handleDragAndDrop(
return handled;
}
-void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group)
+void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience)
{
+ if(is_experience)
+ {
+ LLFloaterReg::showInstance("experience_profile", avatar_id, true);
+ return;
+ }
+
if (is_group)
LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id));
else
@@ -230,10 +236,11 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
// Should we show a group or an avatar inspector?
bool is_group = hit_item->isGroup();
+ bool is_experience = hit_item->isExperience();
LLToolTip::Params params;
params.background_visible( false );
- params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) );
+ params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience) );
params.delay_time(0.0f); // spawn instantly on hover
params.image( icon );
params.message("");
@@ -295,7 +302,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
const std::string& prefix)
{
LLUUID id = name_item.value().asUUID();
- LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP);
+ LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP, name_item.target() == EXPERIENCE);
if (!item) return NULL;
@@ -353,6 +360,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
}
break;
}
+ case EXPERIENCE:
+ // just use supplied name
default:
break;
}
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 515962df7d..19ce3c7aed 100755
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -44,22 +44,30 @@ class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameLi
public:
bool isGroup() const { return mIsGroup; }
void setIsGroup(bool is_group) { mIsGroup = is_group; }
+ bool isExperience() const { return mIsExperience; }
+ void setIsExperience(bool is_experience) { mIsExperience = is_experience; }
protected:
friend class LLNameListCtrl;
LLNameListItem( const LLScrollListItem::Params& p )
- : LLScrollListItem(p), mIsGroup(false)
+ : LLScrollListItem(p), mIsGroup(false), mIsExperience(false)
{
}
LLNameListItem( const LLScrollListItem::Params& p, bool is_group )
- : LLScrollListItem(p), mIsGroup(is_group)
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(false)
+ {
+ }
+
+ LLNameListItem( const LLScrollListItem::Params& p, bool is_group, bool is_experience )
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(is_experience)
{
}
private:
bool mIsGroup;
+ bool mIsExperience;
};
@@ -73,7 +81,8 @@ public:
{
INDIVIDUAL,
GROUP,
- SPECIAL
+ SPECIAL,
+ EXPERIENCE
} ENameType;
// provide names for enums
@@ -160,7 +169,7 @@ public:
/*virtual*/ void mouseOverHighlightNthItem( S32 index );
private:
- void showInspector(const LLUUID& avatar_id, bool is_group);
+ void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, LLHandle<LLNameListItem> item);
private:
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 3e7f05b5e1..7a183cb298 100755
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -277,22 +277,6 @@ protected:
virtual void initChannel() {};
};
-/**
- * Handler for outbox notifications
- */
-class LLOutboxNotification : public LLSystemNotificationHandler
-{
-public:
- LLOutboxNotification();
- virtual ~LLOutboxNotification() {};
- virtual void onChange(LLNotificationPtr p) { }
- virtual void onDelete(LLNotificationPtr p);
- virtual bool processNotification(const LLNotificationPtr& p);
-
-protected:
- virtual void initChannel() {};
-};
-
class LLHandlerUtil
{
public:
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
new file mode 100644
index 0000000000..8cdc2d7c0b
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -0,0 +1,645 @@
+/**
+ * @file llnotificationlistitem.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h" // must be first include
+
+#include "llnotificationlistitem.h"
+
+#include "llagent.h"
+#include "llgroupactions.h"
+#include "llinventoryicon.h"
+#include "llwindow.h"
+#include "v4color.h"
+#include "lltrans.h"
+#include "lluicolortable.h"
+#include "message.h"
+#include "llnotificationsutil.h"
+#include <boost/regex.hpp>
+
+LLNotificationListItem::LLNotificationListItem(const Params& p) : LLPanel(p),
+ mParams(p),
+ mTitleBox(NULL),
+ mExpandBtn(NULL),
+ mCondenseBtn(NULL),
+ mCloseBtn(NULL),
+ mCondensedViewPanel(NULL),
+ mExpandedViewPanel(NULL),
+ mCondensedHeight(0),
+ mExpandedHeight(0),
+ mExpandedHeightResize(0),
+ mExpanded(false)
+{
+ mNotificationName = p.notification_name;
+}
+
+BOOL LLNotificationListItem::postBuild()
+{
+ BOOL rv = LLPanel::postBuild();
+ mTitleBox = getChild<LLTextBox>("notification_title");
+ mTitleBoxExp = getChild<LLTextBox>("notification_title_exp");
+ mNoticeTextExp = getChild<LLChatEntry>("notification_text_exp");
+
+ mTimeBox = getChild<LLTextBox>("notification_time");
+ mTimeBoxExp = getChild<LLTextBox>("notification_time_exp");
+ mExpandBtn = getChild<LLButton>("expand_btn");
+ mCondenseBtn = getChild<LLButton>("condense_btn");
+ mCloseBtn = getChild<LLButton>("close_btn");
+ mCloseBtnExp = getChild<LLButton>("close_expanded_btn");
+
+ mTitleBox->setValue(mParams.title);
+ mTitleBoxExp->setValue(mParams.title);
+ mNoticeTextExp->setValue(mParams.title);
+ mNoticeTextExp->setEnabled(FALSE);
+ mNoticeTextExp->setTextExpandedCallback(boost::bind(&LLNotificationListItem::reshapeNotification, this));
+
+ mTitleBox->setContentTrusted(false);
+ mTitleBoxExp->setContentTrusted(false);
+ mNoticeTextExp->setContentTrusted(false);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp));
+
+ mExpandBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickExpandBtn,this));
+ mCondenseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCondenseBtn,this));
+
+ //mCloseBtn and mCloseExpandedBtn share the same callback
+ mCloseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+ mCloseBtnExp->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+
+ mCondensedViewPanel = getChild<LLPanel>("layout_panel_condensed_view");
+ mExpandedViewPanel = getChild<LLPanel>("layout_panel_expanded_view");
+
+ std::string expanded_height_str = getString("item_expanded_height");
+ std::string condensed_height_str = getString("item_condensed_height");
+
+ mExpandedHeight = (S32)atoi(expanded_height_str.c_str());
+ mCondensedHeight = (S32)atoi(condensed_height_str.c_str());
+
+ setExpanded(FALSE);
+
+ return rv;
+}
+
+LLNotificationListItem::~LLNotificationListItem()
+{
+}
+
+//static
+std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_stamp, ETimeType time_type)
+{
+ std::string timeStr;
+ switch(time_type)
+ {
+ case Local:
+ timeStr = "[" + LLTrans::getString("LTimeMthNum") + "]/["
+ +LLTrans::getString("LTimeDay")+"]/["
+ +LLTrans::getString("LTimeYear")+"] ["
+ +LLTrans::getString("LTimeHour")+"]:["
+ +LLTrans::getString("LTimeMin")+ "]";
+ break;
+ case UTC:
+ timeStr = "[" + LLTrans::getString("UTCTimeMth") + "]/["
+ +LLTrans::getString("UTCTimeDay")+"]/["
+ +LLTrans::getString("UTCTimeYr")+"] ["
+ +LLTrans::getString("UTCTimeHr")+"]:["
+ +LLTrans::getString("UTCTimeMin")+"] ["
+ +LLTrans::getString("UTCTimeTimezone")+"]";
+ break;
+ case SLT:
+ default:
+ timeStr = "[" + LLTrans::getString("TimeMonth") + "]/["
+ +LLTrans::getString("TimeDay")+"]/["
+ +LLTrans::getString("TimeYear")+"] ["
+ +LLTrans::getString("TimeHour")+"]:["
+ +LLTrans::getString("TimeMin")+"]";
+ break;
+ }
+ LLSD substitution;
+ substitution["datetime"] = time_stamp;
+ LLStringUtil::format(timeStr, substitution);
+ return timeStr;
+}
+
+void LLNotificationListItem::onClickCloseBtn()
+{
+ mOnItemClose(this);
+ close();
+}
+
+BOOL LLNotificationListItem::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ BOOL res = LLPanel::handleMouseUp(x, y, mask);
+ mOnItemClick(this);
+ return res;
+}
+
+void LLNotificationListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+}
+
+void LLNotificationListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+}
+
+//static
+LLNotificationListItem* LLNotificationListItem::create(const Params& p)
+{
+ if (LLNotificationListItem::getGroupInviteTypes().count(p.notification_name))
+ {
+ return new LLGroupInviteNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getGroupNoticeTypes().count(p.notification_name))
+ {
+ return new LLGroupNoticeNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getTransactionTypes().count(p.notification_name))
+ {
+ return new LLTransactionNotificationListItem(p);
+ }
+ return new LLSystemNotificationListItem(p);
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getGroupInviteTypes()
+{
+ return LLGroupInviteNotificationListItem::getTypes();
+}
+
+
+std::set<std::string> LLNotificationListItem::getGroupNoticeTypes()
+{
+ return LLGroupNoticeNotificationListItem::getTypes();
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getTransactionTypes()
+{
+ return LLTransactionNotificationListItem::getTypes();
+}
+
+void LLNotificationListItem::onClickExpandBtn()
+{
+ setExpanded(TRUE);
+}
+
+void LLNotificationListItem::onClickCondenseBtn()
+{
+ setExpanded(FALSE);
+}
+
+void LLNotificationListItem::reshapeNotification()
+{
+ if(mExpanded)
+ {
+ S32 width = this->getRect().getWidth();
+ this->reshape(width, mNoticeTextExp->getRect().getHeight() + mExpandedHeight, FALSE);
+ }
+}
+
+void LLNotificationListItem::setExpanded(BOOL value)
+{
+ mCondensedViewPanel->setVisible(!value);
+ mExpandedViewPanel->setVisible(value);
+ S32 width = this->getRect().getWidth();
+
+ if (value)
+ {
+ this->reshape(width, mNoticeTextExp->getRect().getHeight() + mExpandedHeight, FALSE);
+ }
+ else
+ {
+ this->reshape(width, mCondensedHeight, FALSE);
+ }
+ mExpanded = value;
+
+}
+
+std::set<std::string> LLGroupInviteNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("JoinGroup");
+ return types;
+}
+
+std::set<std::string> LLGroupNoticeNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("GroupNotice");
+ return types;
+}
+
+std::set<std::string> LLTransactionNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("PaymentReceived");
+ types.insert("PaymentSent");
+ return types;
+}
+
+LLGroupNotificationListItem::LLGroupNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSenderOrFeeBox(NULL)
+{
+}
+
+LLGroupInviteNotificationListItem::LLGroupInviteNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLGroupInviteNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+ setFee(mParams.fee);
+ mInviteButtonPanel = getChild<LLPanel>("button_panel");
+ mInviteButtonPanel->setVisible(TRUE);
+ mJoinBtn = getChild<LLButton>("join_btn");
+ mDeclineBtn = getChild<LLButton>("decline_btn");
+ mInfoBtn = getChild<LLButton>("info_btn");
+
+ //invitation with any non-default group role, doesn't have newline characters at the end unlike simple invitations
+ std::string invitation_desc = mNoticeTextExp->getValue().asString();
+ boost::regex pattern = boost::regex("\n\n$", boost::regex::perl|boost::regex::icase);
+ boost::match_results<std::string::const_iterator> matches;
+ if(!boost::regex_search(invitation_desc, matches, pattern))
+ {
+ invitation_desc += "\n\n";
+ mNoticeTextExp->setValue(invitation_desc);
+ }
+
+ mJoinBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickJoinBtn,this));
+ mDeclineBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickDeclineBtn,this));
+ mInfoBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickInfoBtn,this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ return rv;
+}
+
+void LLGroupInviteNotificationListItem::onClickJoinBtn()
+{
+ if (!gAgent.canJoinGroups())
+ {
+ LLNotificationsUtil::add("JoinedTooManyGroups");
+ return;
+ }
+
+ if(mParams.fee > 0)
+ {
+ LLSD args;
+ args["COST"] = llformat("%d", mParams.fee);
+ // Set the fee for next time to 0, so that we don't keep
+ // asking about a fee.
+ LLSD next_payload;
+ next_payload["group_id"]= mParams.group_id;
+ next_payload["transaction_id"]= mParams.transaction_id;
+ next_payload["fee"] = 0;
+ LLNotificationsUtil::add("JoinGroupCanAfford", args, next_payload);
+ }
+ else
+ {
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_ACCEPT,
+ mParams.transaction_id);
+ }
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickDeclineBtn()
+{
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_DECLINE,
+ mParams.transaction_id);
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickInfoBtn()
+{
+ LLGroupActions::show(mParams.group_id);
+}
+
+void LLGroupInviteNotificationListItem::setFee(S32 fee)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_FEE]"] = llformat("%d", fee);
+ std::string fee_text = getString("group_fee_text", string_args);
+ mSenderOrFeeBox->setValue(fee_text);
+ mSenderOrFeeBoxExp->setValue(fee_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+}
+
+LLGroupNoticeNotificationListItem::LLGroupNoticeNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p),
+ mAttachmentPanel(NULL),
+ mAttachmentTextBox(NULL),
+ mAttachmentIcon(NULL),
+ mAttachmentIconExp(NULL),
+ mInventoryOffer(NULL)
+{
+ if (mParams.inventory_offer.isDefined())
+ {
+ mInventoryOffer = new LLOfferInfo(mParams.inventory_offer);
+ }
+
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+LLGroupNoticeNotificationListItem::~LLGroupNoticeNotificationListItem()
+{
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+BOOL LLGroupNoticeNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+
+ mAttachmentTextBox = getChild<LLTextBox>("attachment_text");
+ mAttachmentIcon = getChild<LLIconCtrl>("attachment_icon");
+ mAttachmentIconExp = getChild<LLIconCtrl>("attachment_icon_exp");
+ mAttachmentPanel = getChild<LLPanel>("attachment_panel");
+ mAttachmentPanel->setVisible(FALSE);
+
+
+ mTitleBox->setValue(mParams.subject);
+ mTitleBoxExp->setValue(mParams.subject);
+ mNoticeTextExp->setValue(mParams.message);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ //Workaround: in case server timestamp is 0 - we use the time when notification was actually received
+ if (mParams.time_stamp.isNull())
+ {
+ mTimeBox->setValue(buildNotificationDate(mParams.received_time, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time, UTC));
+ }
+ setSender(mParams.sender);
+
+ if (mInventoryOffer != NULL)
+ {
+ mAttachmentTextBox->setValue(mInventoryOffer->mDesc);
+ mAttachmentTextBox->setVisible(TRUE);
+ mAttachmentIcon->setVisible(TRUE);
+
+ std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType,
+ LLInventoryType::IT_TEXTURE);
+ mAttachmentIconExp->setValue(icon_name);
+ mAttachmentIconExp->setVisible(TRUE);
+
+ mAttachmentTextBox->setClickedCallback(boost::bind(
+ &LLGroupNoticeNotificationListItem::onClickAttachment, this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ mAttachmentPanel->setVisible(TRUE);
+ }
+ return rv;
+}
+
+BOOL LLGroupNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+
+ mGroupIcon = getChild<LLGroupIconCtrl>("group_icon");
+ mGroupIconExp = getChild<LLGroupIconCtrl>("group_icon_exp");
+ mGroupNameBoxExp = getChild<LLTextBox>("group_name_exp");
+
+ mGroupIcon->setValue(mParams.group_id);
+ mGroupIconExp->setValue(mParams.group_id);
+
+ mGroupIcon->setVisible(TRUE);
+ mGroupIconExp->setVisible(TRUE);
+
+ mGroupId = mParams.group_id;
+
+ mSenderOrFeeBox = getChild<LLTextBox>("sender_or_fee_box");
+ mSenderOrFeeBoxExp = getChild<LLTextBox>("sender_or_fee_box_exp");
+
+ LLSD value(mParams.group_id);
+ setGroupId(value);
+
+ return rv;
+}
+
+void LLGroupNotificationListItem::changed(LLGroupChange gc)
+{
+ if (GC_PROPERTIES == gc)
+ {
+ updateFromCache();
+ LLGroupMgr::getInstance()->removeObserver(this);
+ }
+}
+
+bool LLGroupNotificationListItem::updateFromCache()
+{
+ LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mGroupId);
+ if (!group_data) return false;
+ setGroupName(group_data->mName);
+ return true;
+}
+
+void LLGroupNotificationListItem::setGroupId(const LLUUID& value)
+{
+ LLGroupMgr* gm = LLGroupMgr::getInstance();
+ if (mGroupId.notNull())
+ {
+ gm->removeObserver(this);
+
+
+ mID = mGroupId;
+
+ // Check if cache already contains image_id for that group
+ if (!updateFromCache())
+ {
+ gm->addObserver(this);
+ gm->sendGroupPropertiesRequest(mGroupId);
+ }
+ }
+}
+
+void LLGroupNotificationListItem::setGroupName(std::string name)
+{
+ if (!name.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_NAME]"] = llformat("%s", name.c_str());
+ std::string group_box_str = getString("group_name_text", string_args);
+ mGroupNameBoxExp->setValue(group_box_str);
+ mGroupNameBoxExp->setVisible(TRUE);
+ }
+ else
+ {
+ mGroupNameBoxExp->setValue(LLStringUtil::null);
+ mGroupNameBoxExp->setVisible(FALSE);
+ }
+}
+
+void LLGroupNoticeNotificationListItem::setSender(std::string sender)
+{
+ if (!sender.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[SENDER_RESIDENT]"] = llformat("%s", sender.c_str());
+ std::string sender_text = getString("sender_resident_text", string_args);
+ mSenderOrFeeBox->setValue(sender_text);
+ mSenderOrFeeBoxExp->setValue(sender_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+ } else {
+ mSenderOrFeeBox->setValue(LLStringUtil::null);
+ mSenderOrFeeBoxExp->setValue(LLStringUtil::null);
+ mSenderOrFeeBox->setVisible(FALSE);
+ mSenderOrFeeBoxExp->setVisible(FALSE);
+ }
+}
+void LLGroupNoticeNotificationListItem::close()
+{
+ // The group notice dialog may be an inventory offer.
+ // If it has an inventory save button and that button is still enabled
+ // Then we need to send the inventory declined message
+ if (mInventoryOffer != NULL)
+ {
+ mInventoryOffer->forceResponse(IOR_DECLINE);
+ mInventoryOffer = NULL;
+ }
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+void LLGroupNoticeNotificationListItem::onClickAttachment()
+{
+ if (mInventoryOffer != NULL) {
+ mInventoryOffer->forceResponse(IOR_ACCEPT);
+
+ static const LLUIColor textColor = LLUIColorTable::instance().getColor(
+ "GroupNotifyDimmedTextColor");
+ mAttachmentTextBox->setColor(textColor);
+ mAttachmentIconExp->setEnabled(FALSE);
+
+ //if attachment isn't openable - notify about saving
+ if (!isAttachmentOpenable(mInventoryOffer->mType)) {
+ LLNotifications::instance().add("AttachmentSaved", LLSD(), LLSD());
+ }
+
+ mInventoryOffer = NULL;
+ }
+}
+
+//static
+bool LLGroupNoticeNotificationListItem::isAttachmentOpenable(LLAssetType::EType type)
+{
+ switch (type)
+ {
+ case LLAssetType::AT_LANDMARK:
+ case LLAssetType::AT_NOTECARD:
+ case LLAssetType::AT_IMAGE_JPEG:
+ case LLAssetType::AT_IMAGE_TGA:
+ case LLAssetType::AT_TEXTURE:
+ case LLAssetType::AT_TEXTURE_TGA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+LLTransactionNotificationListItem::LLTransactionNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mAvatarIcon(NULL)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLTransactionNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ mAvatarIconExp = getChild<LLAvatarIconCtrl>("avatar_icon_exp");
+ mAvatarIcon->setValue("System_Notification");
+ mAvatarIconExp->setValue("System_Notification");
+
+ mAvatarIcon->setVisible(TRUE);
+ mAvatarIconExp->setVisible(TRUE);
+ if((GOVERNOR_LINDEN_ID == mParams.paid_to_id) ||
+ (GOVERNOR_LINDEN_ID == mParams.paid_from_id))
+ {
+ return rv;
+ }
+
+ if (mParams.notification_name == "PaymentReceived")
+ {
+ mAvatarIcon->setValue(mParams.paid_from_id);
+ mAvatarIconExp->setValue(mParams.paid_from_id);
+ }
+ else if (mParams.notification_name == "PaymentSent")
+ {
+ mAvatarIcon->setValue(mParams.paid_to_id);
+ mAvatarIconExp->setValue(mParams.paid_to_id);
+ }
+
+ return rv;
+}
+
+LLSystemNotificationListItem::LLSystemNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSystemNotificationIcon(NULL),
+ mIsCaution(false)
+{
+ buildFromFile("panel_notification_list_item.xml");
+ mIsCaution = p.notification_priority >= NOTIFICATION_PRIORITY_HIGH;
+ if (mIsCaution)
+ {
+ mTitleBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTitleBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mNoticeTextExp->setReadOnlyColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ }
+}
+
+BOOL LLSystemNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mSystemNotificationIcon = getChild<LLIconCtrl>("system_notification_icon");
+ mSystemNotificationIconExp = getChild<LLIconCtrl>("system_notification_icon_exp");
+ if (mSystemNotificationIcon)
+ mSystemNotificationIcon->setVisible(TRUE);
+ if (mSystemNotificationIconExp)
+ mSystemNotificationIconExp->setVisible(TRUE);
+ return rv;
+}
diff --git a/indra/newview/llnotificationlistitem.h b/indra/newview/llnotificationlistitem.h
new file mode 100644
index 0000000000..9a4ce2be4b
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.h
@@ -0,0 +1,250 @@
+/**
+ * @file llnotificationlistitem.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONLISTITEM_H
+#define LL_LLNOTIFICATIONLISTITEM_H
+
+#include "llpanel.h"
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "llviewertexteditor.h"
+#include "llbutton.h"
+#include "llgroupiconctrl.h"
+#include "llavatariconctrl.h"
+#include "llchatentry.h"
+#include "llgroupmgr.h"
+#include "llviewermessage.h"
+
+#include <string>
+
+class LLNotificationListItem : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ LLUUID notification_id;
+ LLUUID transaction_id;
+ LLUUID group_id;
+ LLUUID paid_from_id;
+ LLUUID paid_to_id;
+ std::string notification_name;
+ std::string title;
+ std::string subject;
+ std::string message;
+ std::string sender;
+ S32 fee;
+ LLDate time_stamp;
+ LLDate received_time;
+ LLSD inventory_offer;
+ e_notification_priority notification_priority;
+ Params() {};
+ };
+
+ static LLNotificationListItem* create(const Params& p);
+
+ static std::set<std::string> getTransactionTypes();
+ static std::set<std::string> getGroupInviteTypes();
+ static std::set<std::string> getGroupNoticeTypes();
+
+ // title
+ void setTitle( std::string title );
+
+ // get item's ID
+ LLUUID getID() { return mParams.notification_id; }
+ std::string& getTitle() { return mTitle; }
+ std::string& getNotificationName() { return mNotificationName; }
+
+ // handlers
+ virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+ virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
+ //callbacks
+ typedef boost::function<void (LLNotificationListItem* item)> item_callback_t;
+ typedef boost::signals2::signal<void (LLNotificationListItem* item)> item_signal_t;
+ item_signal_t mOnItemClose;
+ item_signal_t mOnItemClick;
+ boost::signals2::connection setOnItemCloseCallback(item_callback_t cb) { return mOnItemClose.connect(cb); }
+ boost::signals2::connection setOnItemClickCallback(item_callback_t cb) { return mOnItemClick.connect(cb); }
+
+ virtual bool showPopup() { return true; }
+ void setExpanded(BOOL value);
+ virtual BOOL postBuild();
+ void reshapeNotification();
+
+ typedef enum e_time_type
+ {
+ SLT = 1,
+ Local = 2,
+ UTC = 3,
+ }ETimeType;
+
+protected:
+ LLNotificationListItem(const Params& p);
+ virtual ~LLNotificationListItem();
+
+ static std::string buildNotificationDate(const LLDate& time_stamp, ETimeType time_type = SLT);
+ void onClickExpandBtn();
+ void onClickCondenseBtn();
+ void onClickCloseBtn();
+ virtual void close() {};
+
+ Params mParams;
+ LLTextBox* mTitleBox;
+ LLTextBox* mTitleBoxExp;
+ LLChatEntry* mNoticeTextExp;
+ LLTextBox* mTimeBox;
+ LLTextBox* mTimeBoxExp;
+ LLButton* mExpandBtn;
+ LLButton* mCondenseBtn;
+ LLButton* mCloseBtn;
+ LLButton* mCloseBtnExp;
+ LLPanel* mCondensedViewPanel;
+ LLPanel* mExpandedViewPanel;
+ std::string mTitle;
+ std::string mNotificationName;
+ S32 mCondensedHeight;
+ S32 mExpandedHeight;
+ S32 mExpandedHeightResize;
+ bool mExpanded;
+};
+
+class LLGroupNotificationListItem
+ : public LLNotificationListItem, public LLGroupMgrObserver
+{
+public:
+ virtual BOOL postBuild();
+
+ void setGroupId(const LLUUID& value);
+ // LLGroupMgrObserver observer trigger
+ virtual void changed(LLGroupChange gc);
+
+ friend class LLNotificationListItem;
+protected:
+ LLGroupNotificationListItem(const Params& p);
+
+ LLGroupIconCtrl* mGroupIcon;
+ LLGroupIconCtrl* mGroupIconExp;
+ LLUUID mGroupId;
+ LLTextBox* mSenderOrFeeBox;
+ LLTextBox* mSenderOrFeeBoxExp;
+ LLTextBox* mGroupNameBoxExp;
+
+private:
+ LLGroupNotificationListItem(const LLGroupNotificationListItem &);
+ LLGroupNotificationListItem & operator=(LLGroupNotificationListItem &);
+
+ void setGroupName(std::string name);
+ bool updateFromCache();
+};
+
+class LLGroupInviteNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupInviteNotificationListItem(const Params& p);
+ LLGroupInviteNotificationListItem(const LLGroupInviteNotificationListItem &);
+ LLGroupInviteNotificationListItem & operator=(LLGroupInviteNotificationListItem &);
+
+ void setFee(S32 fee);
+
+ void onClickJoinBtn();
+ void onClickDeclineBtn();
+ void onClickInfoBtn();
+
+ LLPanel* mInviteButtonPanel;
+ LLButton* mJoinBtn;
+ LLButton* mDeclineBtn;
+ LLButton* mInfoBtn;
+};
+
+class LLGroupNoticeNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ ~LLGroupNoticeNotificationListItem();
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupNoticeNotificationListItem(const Params& p);
+ LLGroupNoticeNotificationListItem(const LLGroupNoticeNotificationListItem &);
+ LLGroupNoticeNotificationListItem & operator=(LLGroupNoticeNotificationListItem &);
+
+ void setSender(std::string sender);
+ void onClickAttachment();
+ /*virtual*/ void close();
+
+ static bool isAttachmentOpenable(LLAssetType::EType);
+
+ LLPanel* mAttachmentPanel;
+ LLTextBox* mAttachmentTextBox;
+ LLIconCtrl* mAttachmentIcon;
+ LLIconCtrl* mAttachmentIconExp;
+ LLOfferInfo* mInventoryOffer;
+};
+
+class LLTransactionNotificationListItem : public LLNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLTransactionNotificationListItem(const Params& p);
+ LLTransactionNotificationListItem(const LLTransactionNotificationListItem &);
+ LLTransactionNotificationListItem & operator=(LLTransactionNotificationListItem &);
+ LLAvatarIconCtrl* mAvatarIcon;
+ LLAvatarIconCtrl* mAvatarIconExp;
+};
+
+class LLSystemNotificationListItem : public LLNotificationListItem
+{
+public:
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLSystemNotificationListItem(const Params& p);
+ LLSystemNotificationListItem(const LLSystemNotificationListItem &);
+ LLSystemNotificationListItem & operator=(LLSystemNotificationListItem &);
+ LLIconCtrl* mSystemNotificationIcon;
+ LLIconCtrl* mSystemNotificationIconExp;
+ bool mIsCaution;
+};
+
+#endif // LL_LLNOTIFICATIONLISTITEM_H
+
+
diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/llnotificationlistview.cpp
index c4809bc8e7..9dce68c9c6 100755..100644
--- a/indra/newview/lltexturestatsuploader.cpp
+++ b/indra/newview/llnotificationlistview.cpp
@@ -1,10 +1,10 @@
/**
- * @file lltexturerstats.cpp
- * @brief texture stats upload class
+ * @file llnotificationlistview.cpp
+ * @brief
*
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2015, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,27 +23,22 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-
#include "llviewerprecompiledheaders.h"
-#include "lltexturestatsuploader.h"
+#include "llnotificationlistview.h"
+
+static const LLDefaultChildRegistry::Register<LLNotificationListView> notification_list_view("notification_list_view");
-#include "llhttpclient.h"
+LLNotificationListView::LLNotificationListView(const Params& p)
+ : LLFlatListView(p)
+{}
+LLNotificationListView::~LLNotificationListView()
+{}
-// static
-void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)
+bool LLNotificationListView::addNotification(LLNotificationListItem * item)
{
- if ( texture_cap_url != "" )
- {
- LLHTTPClient::post(texture_cap_url, texture_stats, NULL);
- }
- else
- {
- LL_INFOS() << "Not sending texture stats: "
- << texture_stats
- << " as there is no cap url."
- << LL_ENDL;
- }
+ return LLFlatListView::addItem(item, item->getID(), ADD_TOP);
}
+//EOF
diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/llnotificationlistview.h
index ac268c2516..307ad87789 100755..100644
--- a/indra/newview/lltexturestatsuploader.h
+++ b/indra/newview/llnotificationlistview.h
@@ -1,10 +1,10 @@
/**
- * @file lltexturestatsuploader.h
- * @brief Class to send the texture stats to the simulatore
+ * @file llnotificationlistview.h
+ * @brief LLNotificationListView class to support notifications list contained in enclosing floater.
*
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2015, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,17 +24,26 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLTEXTURESTATSUPLOADER_H
-#define LL_LLTEXTURESTATSUPLOADER_H
+#ifndef LL_LLNOTIFICATIONLISTVIEW_H
+#define LL_LLNOTIFICATIONLISTVIEW_H
-#include "llappviewer.h"
+#include "llflatlistview.h"
+#include "llnotificationlistitem.h"
-// utility functions to capture data on texture download speeds and send to simulator periodically
-
-class LLTextureStatsUploader
+/**
+ * Notification list
+ */
+class LLNotificationListView : public LLFlatListView
{
+ LOG_CLASS(LLNotificationListView);
public:
- static void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);
+ struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> {};
+
+ LLNotificationListView(const Params& p);
+ ~LLNotificationListView();
+ friend class LLUICtrlFactory;
+
+ virtual bool addNotification(LLNotificationListItem * item);
};
-#endif // LL_LLTEXTURESTATSUPLOADER_H
+#endif
diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp
index 152581c5a0..a6f20a9f27 100755
--- a/indra/newview/llnotificationmanager.cpp
+++ b/indra/newview/llnotificationmanager.cpp
@@ -61,7 +61,6 @@ void LLNotificationManager::init()
mChannels.push_back(new LLOfferHandler());
mChannels.push_back(new LLHintHandler());
mChannels.push_back(new LLBrowserNotification());
- mChannels.push_back(new LLOutboxNotification());
mChannels.push_back(new LLIMHandler());
mChatHandler = boost::shared_ptr<LLFloaterIMNearbyChatHandler>(new LLFloaterIMNearbyChatHandler());
@@ -70,7 +69,7 @@ void LLNotificationManager::init()
//--------------------------------------------------------------------------
void LLNotificationManager::onChat(const LLChat& msg, const LLSD &args)
{
- if(mChatHandler)
- mChatHandler->processChat(msg, args);
- }
+ if(mChatHandler)
+ mChatHandler->processChat(msg, args);
+}
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 9bd6007772..b7e1b2d3a4 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1168,6 +1168,8 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
targetPanel->setVisible(show);
toggleTypeSpecificControls(type);
+ // Update type controls here
+ updateTypeSpecificControls(type);
if (show)
{
@@ -1179,7 +1181,6 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
mNameEditor->setText(mWearableItem->getName());
updatePanelPickerControls(type);
- updateTypeSpecificControls(type);
// clear and rebuild visual param list
U8 num_subparts = wearable_entry->mSubparts.size();
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
index 20fe0c52fa..32ec4930ab 100644
--- a/indra/newview/llpanelexperiencelisteditor.cpp
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -33,6 +33,7 @@
#include "llfloaterexperiencepicker.h"
#include "llfloaterreg.h"
#include "llhandle.h"
+#include "llnamelistctrl.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
@@ -54,7 +55,7 @@ LLPanelExperienceListEditor::LLPanelExperienceListEditor()
BOOL LLPanelExperienceListEditor::postBuild()
{
- mItems = getChild<LLScrollListCtrl>("experience_list");
+ mItems = getChild<LLNameListCtrl>("experience_list");
mAdd = getChild<LLButton>("btn_add");
mRemove = getChild<LLButton>("btn_remove");
mProfile = getChild<LLButton>("btn_profile");
@@ -178,12 +179,13 @@ void LLPanelExperienceListEditor::onItems()
{
const LLUUID& experience = *it;
item["id"]=experience;
+ item["target"] = LLNameListCtrl::EXPERIENCE;
LLSD& columns = item["columns"];
columns[0]["column"] = "experience_name";
columns[0]["value"] = getString("loading");
mItems->addElement(item);
- LLExperienceCache::getInstance()->get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
+ LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h
index f69f0509be..bc9867752d 100644
--- a/indra/newview/llpanelexperiencelisteditor.h
+++ b/indra/newview/llpanelexperiencelisteditor.h
@@ -31,6 +31,7 @@
#include "lluuid.h"
#include <set>
+class LLNameListCtrl;
class LLScrollListCtrl;
class LLButton;
class LLFloaterExperiencePicker;
@@ -82,7 +83,7 @@ private:
uuid_list_t mExperienceIds;
- LLScrollListCtrl* mItems;
+ LLNameListCtrl* mItems;
filter_list mFilters;
LLButton* mAdd;
LLButton* mRemove;
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index 9329d900b1..d5979b6e96 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -140,7 +140,7 @@ void LLPanelExperienceLog::refresh()
}
const LLSD event = dayArray[i];
LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
- const LLSD& experience = LLExperienceCache::getInstance()->get(id);
+ const LLSD& experience = LLExperienceCache::instance().get(id);
if(experience.isUndefined()){
waiting = true;
waiting_id = id;
@@ -168,7 +168,7 @@ void LLPanelExperienceLog::refresh()
{
mEventList->deleteAllItems();
mEventList->setCommentText(getString("loading"));
- LLExperienceCache::getInstance()->get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
+ LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
}
else
{
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
index 7c19e32e7e..a7f2dbafa2 100644
--- a/indra/newview/llpanelexperiencepicker.cpp
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -42,7 +42,7 @@
#include "llviewercontrol.h"
#include "llfloater.h"
#include "lltrans.h"
-#include "llhttpclient.h" // *TODO: Rider, remove when converting
+#include <boost/regex.hpp>
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
@@ -59,41 +59,6 @@ const static std::string columnSpace = " ";
static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker");
-class LLExperienceSearchResponder : public LLHTTPClient::Responder
-{
-public:
- LLUUID mQueryID;
- LLHandle<LLPanelExperiencePicker> mParent;
-
- LLExperienceSearchResponder(const LLUUID& id, const LLHandle<LLPanelExperiencePicker>& parent) : mQueryID(id), mParent(parent) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- if(mParent.isDead())
- return;
-
- LLPanelExperiencePicker* panel =mParent.get();
- if (panel)
- {
- panel->processResponse(mQueryID, getContent());
- }
- }
-
- /*virtual*/ void httpFailure()
- {
- if(mParent.isDead())
- return;
-
- LLPanelExperiencePicker* panel =mParent.get();
- if (panel)
- {
- panel->processResponse(mQueryID, LLSD());
- }
- LL_WARNS() << "experience picker failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
LLPanelExperiencePicker::LLPanelExperiencePicker()
:LLPanel()
{
@@ -148,6 +113,46 @@ void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* u
void LLPanelExperiencePicker::onBtnFind()
{
mCurrentPage=1;
+ boost::cmatch what;
+ std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
+ const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile");
+ if (boost::regex_match(text.c_str(), what, expression))
+ {
+ LLURI uri(text);
+ LLSD path_array = uri.pathArray();
+ if (path_array.size() == 4)
+ {
+ std::string exp_id = path_array.get(2).asString();
+ LLUUID experience_id(exp_id);
+ if (!experience_id.isNull())
+ {
+ const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
+ if(!experience_details.isUndefined())
+ {
+ std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
+ if(!experience_name_string.empty())
+ {
+ getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string);
+ }
+ }
+ else
+ {
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
+
+ getChildView(BTN_OK)->setEnabled(FALSE);
+ getChildView(BTN_PROFILE)->setEnabled(FALSE);
+
+ getChildView(BTN_RIGHT)->setEnabled(FALSE);
+ getChildView(BTN_LEFT)->setEnabled(FALSE);
+ LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
+ return;
+ }
+ }
+ }
+ }
+
+
find();
}
@@ -164,17 +169,11 @@ void LLPanelExperiencePicker::find()
{
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
mQueryID.generate();
- std::ostringstream url;
- LLViewerRegion* region = gAgent.getRegion();
- std::string cap = region->getCapability("FindExperienceByName");
- if (!cap.empty())
- {
- url << cap << "?page=" << mCurrentPage << "&page_size=30&query=" << LLURI::escape(text);
- LLHTTPClient::get(url.str(), new LLExperienceSearchResponder(mQueryID, getDerivedHandle<LLPanelExperiencePicker>()));
+ LLExperienceCache::instance().findExperienceByName(text, mCurrentPage,
+ boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle<LLPanelExperiencePicker>(), mQueryID, _1));
- }
- getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
getChildView(BTN_OK)->setEnabled(FALSE);
@@ -184,6 +183,18 @@ void LLPanelExperiencePicker::find()
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
+/*static*/
+void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult)
+{
+ if (hparent.isDead())
+ return;
+
+ LLPanelExperiencePicker* panel = hparent.get();
+ if (panel)
+ {
+ panel->processResponse(queryId, foundResult);
+ }
+}
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
@@ -234,13 +245,6 @@ void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLS
mResponse = content;
- const LLSD& experiences=mResponse["experience_keys"];
- LLSD::array_const_iterator it = experiences.beginArray();
- for ( ; it != experiences.endArray(); ++it)
- {
- LLExperienceCache::getInstance()->insert(*it);
- }
-
getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url"));
diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h
index e39ffed70b..97aa04cf4c 100644
--- a/indra/newview/llpanelexperiencepicker.h
+++ b/indra/newview/llpanelexperiencepicker.h
@@ -74,8 +74,9 @@ private:
void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids );
void setAllowMultiple(bool allow_multiple);
-
void find();
+ static void findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult);
+
bool isSelectButtonEnabled();
void processResponse( const LLUUID& query_id, const LLSD& content );
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 9823e84cd9..d7e89b4832 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -307,7 +307,7 @@ private:
LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
}
- object->setTEMaterialParams(face, new_material);
+ object->setTEMaterialParams(face, new_material, TRUE);
return new_material;
}
return NULL;
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index f67a90fd01..342b57ba4a 100755
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -338,7 +338,7 @@ void LLPanelGroup::update(LLGroupChange gc)
group_name_ctrl->setToolTip(group_name);
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
bool join_btn_visible = !is_member && gdatap->mOpenEnrollment;
mButtonJoin->setVisible(join_btn_visible);
@@ -470,7 +470,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
}
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
tab_roles->setVisible(is_member);
tab_notices->setVisible(is_member);
diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp
index 76b68122fb..a88a55ab22 100644
--- a/indra/newview/llpanelgroupexperiences.cpp
+++ b/indra/newview/llpanelgroupexperiences.cpp
@@ -31,45 +31,16 @@
#include "lluictrlfactory.h"
#include "roles_constants.h"
-#include "llhttpclient.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llflatlistview.h"
#include "llpanelexperiences.h"
#include "llsd.h"
-
+#include "llexperiencecache.h"
static LLPanelInjector<LLPanelGroupExperiences> t_panel_group_experiences("panel_group_experiences");
-class LLGroupExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- LLHandle<LLPanelGroupExperiences> mHandle;
-
- LLGroupExperienceResponder(LLHandle<LLPanelGroupExperiences> handle) : mHandle(handle) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- if (mHandle.isDead())
- {
- return;
- }
-
- LLPanelGroupExperiences* panel = mHandle.get();
- if (panel)
- {
- panel->setExperienceList(getContent().get("experience_ids"));
- }
- }
-
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
LLPanelGroupExperiences::LLPanelGroupExperiences()
: LLPanelGroupTab(), mExperiencesList(NULL)
{
@@ -101,14 +72,8 @@ void LLPanelGroupExperiences::activate()
return;
}
- // search for experiences owned by the current group
- std::string url = gAgent.getRegion()->getCapability("GroupExperiences");
- if (!url.empty())
- {
- url += "?" + getGroupID().asString();
-
- LLHTTPClient::get(url, new LLGroupExperienceResponder(getDerivedHandle<LLPanelGroupExperiences>()));
- }
+ LLExperienceCache::instance().getGroupExperiences(getGroupID(),
+ boost::bind(&LLPanelGroupExperiences::groupExperiencesResults, getDerivedHandle<LLPanelGroupExperiences>(), _1));
}
void LLPanelGroupExperiences::setGroupID(const LLUUID& id)
@@ -141,3 +106,19 @@ void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences)
mExperiencesList->addItem(item, public_key);
}
}
+
+/*static*/
+void LLPanelGroupExperiences::groupExperiencesResults(LLHandle<LLPanelGroupExperiences> handle, const LLSD &experiences)
+{
+ if (handle.isDead())
+ {
+ return;
+ }
+
+ LLPanelGroupExperiences* panel = handle.get();
+ if (panel)
+ {
+ panel->setExperienceList(experiences);
+ }
+
+}
diff --git a/indra/newview/llpanelgroupexperiences.h b/indra/newview/llpanelgroupexperiences.h
index ae1ecc1ac5..7c79f77332 100644
--- a/indra/newview/llpanelgroupexperiences.h
+++ b/indra/newview/llpanelgroupexperiences.h
@@ -48,6 +48,9 @@ public:
protected:
LLFlatListView* mExperiencesList;
+
+private:
+ static void groupExperiencesResults(LLHandle<LLPanelGroupExperiences>, const LLSD &);
};
#endif
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 7ffaa05919..b2164c1f21 100755
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -287,11 +287,6 @@ void LLPanelGroupGeneral::activate()
{
LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID);
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
-
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
mFirstUse = FALSE;
}
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index e662a05dfc..866cb8dbef 100755
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -243,56 +243,59 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
LLGroupMgrGroupData::member_list_t::iterator agent_iter =
gdatap->mMembers.find(gAgent.getID());
+ //loop over the agent's roles in the group
+ //then add those roles to the list of roles that the agent
+ //can invite people to be.
+ //if the user is the owner then we add
+ //all of the roles in the group,
+ //else if they have the add to roles power
+ //we add every role but owner,
+ //else if they have the limited add to roles power
+ //we add every role the user is in,
+ //else we just add to everyone
+ bool is_owner = FALSE;
+ bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER);
+ bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ LLGroupMemberData* member_data = NULL;
//get the member data for the agent if it exists
- if ( agent_iter != gdatap->mMembers.end() )
+ if (agent_iter != gdatap->mMembers.end())
{
- LLGroupMemberData* member_data = (*agent_iter).second;
-
- //loop over the agent's roles in the group
- //then add those roles to the list of roles that the agent
- //can invite people to be
- if ( member_data && mRoleNames)
+ member_data = (*agent_iter).second;
+ if (member_data && mRoleNames)
{
- //if the user is the owner then we add
- //all of the roles in the group
- //else if they have the add to roles power
- //we add every role but owner,
- //else if they have the limited add to roles power
- //we add every role the user is in
- //else we just add to everyone
- bool is_owner = member_data->isOwner();
- bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER);
- bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ is_owner = member_data->isOwner();
+ }//end if member data is not null
+ }//end if agent is in the group
+
- LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
- LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
- //populate the role list
- for ( ; rit != end; ++rit)
+ LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
+ LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
+
+ //populate the role list:
+ for ( ; rit != end; ++rit)
+ {
+ LLUUID role_id = (*rit).first;
+ LLRoleData rd;
+ if ( gdatap->getRoleData(role_id,rd) )
+ {
+ // Owners can add any role.
+ if ( is_owner
+ // Even 'can_assign_any' can't add owner role.
+ || (can_assign_any && role_id != gdatap->mOwnerRole)
+ // Add all roles user is in
+ || (can_assign_limited && member_data && member_data->isInRole(role_id))
+ // Everyone role.
+ || role_id == LLUUID::null )
{
- LLUUID role_id = (*rit).first;
- LLRoleData rd;
- if ( gdatap->getRoleData(role_id,rd) )
- {
- // Owners can add any role.
- if ( is_owner
- // Even 'can_assign_any' can't add owner role.
- || (can_assign_any && role_id != gdatap->mOwnerRole)
- // Add all roles user is in
- || (can_assign_limited && member_data->isInRole(role_id))
- // Everyone role.
- || role_id == LLUUID::null )
- {
- mRoleNames->add(rd.mRoleName,
- role_id,
- ADD_BOTTOM);
- }
- }
+ mRoleNames->add(rd.mRoleName,
+ role_id,
+ ADD_BOTTOM);
}
- }//end if member data is not null
- }//end if agent is in the group
+ }
+ }
}
//static
@@ -579,7 +582,8 @@ void LLPanelGroupInvite::updateLists()
{
waiting = true;
}
- if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())
+ if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()
+ && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them
{
if ( mImplementation->mRoleNames )
{
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index c3a10b3fa0..00c204e702 100755
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -350,12 +350,10 @@ void LLPanelGroupRoles::update(LLGroupChange gc)
void LLPanelGroupRoles::activate()
{
+ if (!gAgent.isInGroup(mGroupID)) return;
+
// Start requesting member and role data if needed.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
if (!gdatap || !gdatap->isRoleDataComplete() )
{
@@ -364,13 +362,7 @@ void LLPanelGroupRoles::activate()
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
}
-
- // Check role-member mapping data.
- if (!gdatap || !gdatap->isRoleMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
-
+
// Need this to get base group member powers
if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
{
@@ -1163,7 +1155,37 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
if ( selfp )
{
- selfp->handleEjectMembers();
+ selfp->confirmEjectMembers();
+ }
+}
+
+void LLPanelGroupMembersSubTab::confirmEjectMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
}
}
@@ -1190,6 +1212,16 @@ void LLPanelGroupMembersSubTab::handleEjectMembers()
LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);
}
+bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleEjectMembers();
+ }
+ return false;
+}
+
void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
{
LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
@@ -1327,15 +1359,26 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick()
void LLPanelGroupMembersSubTab::activate()
{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+
LLPanelGroupSubTab::activate();
if(!mActivated)
{
+ if (!gdatap || !gdatap->isMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
+ }
+
+ if (!gdatap || !gdatap->isRoleMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
+ }
+
update(GC_ALL);
mActivated = true;
}
else
{
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
// Members can be removed outside of this tab, checking changes
if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount()))
{
@@ -1636,7 +1679,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
{
// Build a string with info on retrieval progress.
std::ostringstream retrieved;
- if ( !gdatap->isMemberDataComplete() )
+
+ if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() )
+ {
+ // MAINT-5237
+ retrieved << "Member list not available.";
+ }
+ else if ( !gdatap->isMemberDataComplete() )
{
// Still busy retreiving member list.
retrieved << "Retrieving member list (" << gdatap->mMembers.size()
@@ -1783,7 +1832,7 @@ void LLPanelGroupMembersSubTab::updateMembers()
{
mMembersList->setEnabled(TRUE);
}
- else
+ else if (gdatap->mMembers.size())
{
mMembersList->setEnabled(FALSE);
mMembersList->setCommentText(std::string("No match."));
@@ -1801,7 +1850,47 @@ void LLPanelGroupMembersSubTab::updateMembers()
void LLPanelGroupMembersSubTab::onBanMember(void* user_data)
{
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
- self->handleBanMember();
+ self->confirmBanMembers();
+}
+
+void LLPanelGroupMembersSubTab::confirmBanMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+}
+
+bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleBanMember();
+ }
+ return false;
}
void LLPanelGroupMembersSubTab::handleBanMember()
@@ -2111,20 +2200,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
mDeleteRoleButton->setEnabled(FALSE);
}
}
-
- if(!mFirstOpen)
- {
- if (!gdatap || !gdatap->isMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
-
- if (!gdatap || !gdatap->isRoleMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
- }
-
+
if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)
&& gdatap
&& gdatap->isMemberDataComplete()
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 540b24ada6..9a696124a8 100755
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -171,6 +171,7 @@ public:
void handleEjectMembers();
void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members);
bool handleEjectCallback(const LLSD& notification, const LLSD& response);
+ void confirmEjectMembers();
static void onRoleCheck(LLUICtrl* check, void* user_data);
void handleRoleCheck(const LLUUID& role_id,
@@ -178,6 +179,8 @@ public:
static void onBanMember(void* user_data);
void handleBanMember();
+ bool handleBanCallback(const LLSD& notification, const LLSD& response);
+ void confirmBanMembers();
void applyMemberChanges();
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index d4894d4a42..06bb886ae8 100755
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -147,6 +147,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)
}
else
{
+ LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos);
region_name = desc;
}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index f972b320c3..360b144604 100755
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -40,7 +40,6 @@
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
#include "llcombobox.h"
-#include "llcurl.h"
#include "llviewercontrol.h"
#include "llfloaterpreference.h"
#include "llfocusmgr.h"
@@ -435,17 +434,10 @@ void LLPanelLogin::show(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void* callback_data)
{
- // instance management
- if (LLPanelLogin::sInstance)
- {
- LL_WARNS("AppInit") << "Duplicate instance of login view deleted" << LL_ENDL;
- // Don't leave bad pointer in gFocusMgr
- gFocusMgr.setDefaultKeyboardFocus(NULL);
-
- delete LLPanelLogin::sInstance;
- }
-
- new LLPanelLogin(rect, callback, callback_data);
+ if (!LLPanelLogin::sInstance)
+ {
+ new LLPanelLogin(rect, callback, callback_data);
+ }
if( !gFocusMgr.getKeyboardFocus() )
{
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 7aaf9510eb..4229419fce 100755
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -604,7 +604,7 @@ void LLPanelMainInventory::updateItemcountText()
}
else
{
- text = getString("ItemcountUnknown");
+ text = getString("ItemcountUnknown", string_args);
}
mCounterCtrl->setValue(text);
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 2856ea9db1..d7c43c224c 100755
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -319,6 +319,10 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media
// Helper to set media control to media URL as required
void LLPanelMediaSettingsGeneral::updateMediaPreview()
{
+ if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString())
+ {
+ return;
+ }
if ( mHomeURL->getValue().asString().length() > 0 )
{
if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString())
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index dcd0aab3ab..5dd44b4444 100755
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -1739,9 +1739,10 @@ void LLPanelObject::sendSculpt()
return;
LLSculptParams sculpt_params;
+ LLUUID sculpt_id = LLUUID::null;
if (mCtrlSculptTexture)
- sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID());
+ sculpt_id = mCtrlSculptTexture->getImageAssetID();
U8 sculpt_type = 0;
@@ -1765,7 +1766,7 @@ void LLPanelObject::sendSculpt()
if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))
sculpt_type |= LL_SCULPT_FLAG_INVERT;
- sculpt_params.setSculptType(sculpt_type);
+ sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
}
@@ -2000,7 +2001,11 @@ void LLPanelObject::onCancelSculpt(const LLSD& data)
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(!mTextureCtrl)
return;
-
+
+ if(mSculptTextureRevert == LLUUID::null)
+ {
+ mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE);
+ }
mTextureCtrl->setImageAssetID(mSculptTextureRevert);
sendSculpt();
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5977d558d3..de4efc8612 100755
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -85,6 +85,8 @@ static const std::string RECENT_TAB_NAME = "recent_panel";
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+const S32 BASE_MAX_AGENT_GROUPS = 42;
+const S32 PREMIUM_MAX_AGENT_GROUPS = 60;
extern S32 gMaxAgentGroups;
@@ -585,6 +587,7 @@ BOOL LLPanelPeople::postBuild()
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
+ getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this));
mTabContainer = getChild<LLTabContainer>("tabs");
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
@@ -902,8 +905,11 @@ void LLPanelPeople::updateButtons()
LLPanel* groups_panel = mTabContainer->getCurrentPanel();
groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size()));
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d",(gMaxAgentGroups-gAgent.mGroups.size())));
+
+ U32 groups_count = gAgent.mGroups.size();
+ U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0;
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count));
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining));
}
else
{
@@ -1114,6 +1120,14 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
}
}
+void LLPanelPeople::onGroupLimitInfo()
+{
+ LLSD args;
+ args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS;
+ args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS;
+ LLNotificationsUtil::add("GroupLimitInfo", args);
+}
+
void LLPanelPeople::onTabSelected(const LLSD& param)
{
std::string tab_name = getChild<LLPanel>(param.asString())->getName();
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index c1d7a134fa..eb7e76a772 100755
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -93,6 +93,7 @@ private:
// UI callbacks
void onFilterEdit(const std::string& search_string);
+ void onGroupLimitInfo();
void onTabSelected(const LLSD& param);
void onAddFriendButtonClicked();
void onAddFriendWizButtonClicked();
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index d73a5b402e..55c09d85ea 100755
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -432,7 +432,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
mNoPicks = !mPicksList->size();
}
- else if(APT_CLASSIFIEDS == type)
+ else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))
{
LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
if(c_info && getAvatarId() == c_info->target_id)
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 4bcd932d4b..a9a0c30e26 100755
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -921,7 +921,12 @@ void LLPanelPlaces::onBackButtonClicked()
void LLPanelPlaces::togglePickPanel(BOOL visible)
{
if (mPickPanel)
+ {
mPickPanel->setVisible(visible);
+ mPlaceProfile->setVisible(!visible);
+ updateVerbs();
+ }
+
}
void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
@@ -1141,16 +1146,21 @@ void LLPanelPlaces::updateVerbs()
bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE;
bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE;
+ bool is_pick_panel_visible = false;
+ if(mPickPanel)
+ {
+ is_pick_panel_visible = mPickPanel->isInVisibleChain();
+ }
bool have_3d_pos = ! mPosGlobal.isExactlyZero();
- mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
- mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
+ mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
+ mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn);
mSaveBtn->setVisible(isLandmarkEditModeOn);
mCancelBtn->setVisible(isLandmarkEditModeOn);
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
- mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
+ mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index ac9a31ce4e..109013498e 100755
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -313,14 +313,11 @@ void LLPanelTopInfoBar::updateParcelIcons()
bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
bool see_avs = current_parcel->getSeeAVs();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mDamageText->setVisible(allow_damage);
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp
index 2e6937a79f..711a869e82 100755
--- a/indra/newview/llpathfindingmanager.cpp
+++ b/indra/newview/llpathfindingmanager.cpp
@@ -464,7 +464,7 @@ void LLPathfindingManager::navMeshStatusRequestCoro(std::string url, U64 regionH
LLUUID regionUUID = region->getRegionID();
region = NULL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
region = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
@@ -519,7 +519,7 @@ void LLPathfindingManager::navMeshStatusRequestCoro(std::string url, U64 regionH
navMeshPtr->handleNavMeshStart(navMeshStatus);
LLSD postData;
- result = httpAdapter->postAndYield(httpRequest, navMeshURL, postData);
+ result = httpAdapter->postAndSuspend(httpRequest, navMeshURL, postData);
U32 navMeshVersion = navMeshStatus.getVersion();
@@ -545,7 +545,7 @@ void LLPathfindingManager::navAgentStateRequestCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavAgentStateRequest", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -577,7 +577,7 @@ void LLPathfindingManager::navMeshRebakeCoro(std::string url, rebake_navmesh_cal
LLSD postData = LLSD::emptyMap();
postData["command"] = "rebuild";
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -606,11 +606,11 @@ void LLPathfindingManager::linksetObjectsCoro(std::string url, LinksetsResponder
if (putData.isUndefined())
{
- result = httpAdapter->getAndYield(httpRequest, url);
+ result = httpAdapter->getAndSuspend(httpRequest, url);
}
else
{
- result = httpAdapter->putAndYield(httpRequest, url, putData);
+ result = httpAdapter->putAndSuspend(httpRequest, url, putData);
}
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
@@ -642,11 +642,11 @@ void LLPathfindingManager::linksetTerrainCoro(std::string url, LinksetsResponder
if (putData.isUndefined())
{
- result = httpAdapter->getAndYield(httpRequest, url);
+ result = httpAdapter->getAndSuspend(httpRequest, url);
}
else
{
- result = httpAdapter->putAndYield(httpRequest, url, putData);
+ result = httpAdapter->putAndSuspend(httpRequest, url, putData);
}
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
@@ -673,7 +673,7 @@ void LLPathfindingManager::charactersCoro(std::string url, request_id_t requestI
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 4f5d21b6be..ed34190caa 100755
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -87,7 +87,6 @@
#include "llfloatergotoline.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
-#include "llexperienceassociationresponder.h"
#include "llviewerassetupload.h"
const std::string HELLO_LSL =
@@ -1326,7 +1325,7 @@ void LLLiveLSLEditor::buildExperienceList()
position = ADD_TOP;
}
- const LLSD& experience = LLExperienceCache::getInstance()->get(id);
+ const LLSD& experience = LLExperienceCache::instance().get(id);
if(experience.isUndefined())
{
mExperiences->add(getString("loading"), id, position);
@@ -1345,7 +1344,7 @@ void LLLiveLSLEditor::buildExperienceList()
if(!foundAssociated )
{
- const LLSD& experience = LLExperienceCache::getInstance()->get(associated);
+ const LLSD& experience = LLExperienceCache::instance().get(associated);
if(experience.isDefined())
{
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
@@ -1366,11 +1365,13 @@ void LLLiveLSLEditor::buildExperienceList()
if(last.notNull())
{
mExperiences->setEnabled(FALSE);
- LLExperienceCache::getInstance()->get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
+ LLExperienceCache::instance().get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
}
else
{
mExperiences->setEnabled(TRUE);
+ mExperiences->sortByName(TRUE);
+ mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex());
getChild<LLButton>("view_profile")->setVisible(TRUE);
}
}
@@ -2039,8 +2040,9 @@ void LLLiveLSLEditor::loadAsset()
if(item)
{
- ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1));
-
+ LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(),
+ boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1));
+
bool isGodlike = gAgent.isGodlike();
bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE);
mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE);
@@ -2642,8 +2644,12 @@ void LLLiveLSLEditor::onLoad(void* userdata)
void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
- self->mCloseAfterSave = close_after_save;
- self->saveIfNeeded();
+ if(self)
+ {
+ self->mCloseAfterSave = close_after_save;
+ self->mScriptEd->mErrorList->setCommentText("");
+ self->saveIfNeeded();
+ }
}
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index f91a18d8d3..c8cf0faa15 100755
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -618,4 +618,5 @@ void LLPreviewTexture::setObjectID(const LLUUID& object_id)
mAssetStatus = PREVIEW_ASSET_UNLOADED;
loadAsset();
}
+ refreshFromItem();
}
diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp
index 467e9df482..b663df4aae 100755
--- a/indra/newview/llproductinforequest.cpp
+++ b/indra/newview/llproductinforequest.cpp
@@ -73,7 +73,7 @@ void LLProductInfoRequestManager::getLandDescriptionsCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index 1257ee7f94..c17b86783d 100755
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -175,6 +175,10 @@ void LLProgressView::setStartupComplete()
void LLProgressView::setVisible(BOOL visible)
{
+ if (!visible && mFadeFromLoginTimer.getStarted())
+ {
+ mFadeFromLoginTimer.stop();
+ }
// hiding progress view
if (getVisible() && !visible)
{
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index 06bf90c7cb..055ccd5818 100755
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -200,7 +200,7 @@ void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url,
bodyData["region_handle"] = ll_sd_from_U64(regionHandle);
}
- LLSD result = httpAdapter->postAndYield(httpRequest, url, bodyData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, bodyData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
index 43bb7b1596..4f9f83b6f2 100755
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -32,7 +32,6 @@
#include <openssl/evp.h>
#include <openssl/err.h>
#include <map>
-#include "llhttpclient.h"
@@ -99,46 +98,6 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred)
return s << (std::string)cred;
}
-
-// secapiSSLCertVerifyCallback
-// basic callback called when a cert verification is requested.
-// calls SECAPI to validate the context
-// not initialized in the above initialization function, due to unit tests
-// see llappviewer
-
-int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
-{
- LLURLRequest *req = (LLURLRequest *)param;
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
- LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
- LLSD validation_params = LLSD::emptyMap();
- LLURI uri(req->getURL());
- validation_params[CERT_HOSTNAME] = uri.hostName();
- try
- {
- // we rely on libcurl to validate the hostname, as libcurl does more extensive validation
- // leaving our hostname validation call mechanism for future additions with respect to
- // OS native (Mac keyring, windows CAPI) validation.
- store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
- }
- catch (LLCertValidationTrustException& cert_exception)
- {
- LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL;
- return 0;
- }
- catch (LLCertException& cert_exception)
- {
- LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL;
- return 0;
- }
- catch (...)
- {
- LL_WARNS("AppInit") << "cert error " << LL_ENDL;
- return 0;
- }
- return 1;
-}
-
LLSD LLCredential::getLoginParams()
{
LLSD result = LLSD::emptyMap();
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index c01d318f56..6fe3ee31cf 100755
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -489,7 +489,4 @@ void registerSecHandler(const std::string& handler_type,
extern LLPointer<LLSecAPIHandler> gSecAPIHandler;
-int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
-
-
#endif // LL_SECAPI_H
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 4fafbf917b..55bcb3dc65 100755
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2127,7 +2127,7 @@ void LLSelectMgr::selectionRemoveMaterial()
{
LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
LLMaterialMgr::getInstance()->remove(object->getID(),face);
- object->setTEMaterialParams(face, NULL);
+ object->setTEMaterialParams(face, NULL, FALSE);
}
return true;
}
@@ -4950,6 +4950,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
ESendType send_type)
{
LLSelectNode* node;
+ LLSelectNode* linkset_root = NULL;
LLViewerRegion* last_region;
LLViewerRegion* current_region;
@@ -4957,6 +4958,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
S32 packets_sent = 0;
S32 objects_in_this_packet = 0;
+ bool link_operation = message_name == "ObjectLink";
+
//clear update override data (allow next update through)
struct f : public LLSelectedNodeFunctor
{
@@ -5065,6 +5068,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
&& (! gMessageSystem->isSendFull(NULL))
&& (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))
{
+ if (link_operation && linkset_root == NULL)
+ {
+ // linksets over 254 will be split into multiple messages,
+ // but we need to provide same root for all messages or we will get separate linksets
+ linkset_root = node;
+ }
// add another instance of the body of the data
(*pack_body)(node, user_data);
// do any related logging
@@ -5093,6 +5102,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
gMessageSystem->newMessage(message_name.c_str());
(*pack_header)(user_data);
+ if (linkset_root != NULL)
+ {
+ if (current_region != last_region)
+ {
+ // root should be in one region with the child, reset it
+ linkset_root = NULL;
+ }
+ else
+ {
+ // add root instance into new message
+ (*pack_body)(linkset_root, user_data);
+ ++objects_sent;
+ ++objects_in_this_packet;
+ }
+ }
+
// don't move to the next object, we still need to add the
// body data.
}
diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp
index 0e23e2ad10..67ac875428 100755
--- a/indra/newview/llsidepanelinventory.cpp
+++ b/indra/newview/llsidepanelinventory.cpp
@@ -37,7 +37,6 @@
#include "llfloatersidepanelcontainer.h"
#include "llfoldertype.h"
#include "llfolderview.h"
-#include "llhttpclient.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index a7cfc173af..12cbff888d 100755
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -44,7 +44,6 @@
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
-#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "lltrans.h"
@@ -328,7 +327,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience");
tb->setText(getString("loading_experience"));
tb->setVisible(TRUE);
- ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1));
+
+ LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(),
+ boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1));
}
//////////////////////
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 17ecfab4fb..2548d730f0 100755
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -370,18 +370,25 @@ void LLSidepanelTaskInfo::refresh()
// Update creator text field
getChildView("Creator:")->setEnabled(TRUE);
+
std::string creator_name;
- LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
+ LLUUID creator_id;
+ LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
- getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
- getChildView("Creator Name")->setEnabled(TRUE);
+ if(creator_id != mCreatorID )
+ {
+ mDACreatorName->setValue(creator_name);
+ mCreatorID = creator_id;
+ }
+ mDACreatorName->setEnabled(TRUE);
// Update owner text field
getChildView("Owner:")->setEnabled(TRUE);
std::string owner_name;
- const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name);
- if (mOwnerID.isNull())
+ LLUUID owner_id;
+ const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
+ if (owner_id.isNull())
{
if (LLSelectMgr::getInstance()->selectIsGroupOwned())
{
@@ -402,7 +409,12 @@ void LLSidepanelTaskInfo::refresh()
}
}
}
- getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+
+ if(owner_id.isNull() || (owner_id != mOwnerID))
+ {
+ mDAOwnerName->setValue(owner_name);
+ mOwnerID = owner_id;
+ }
getChildView("Owner Name")->setEnabled(TRUE);
// update group text field
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 728fc69723..a8e012bfa1 100755
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -271,7 +271,14 @@ LLSLURL::LLSLURL(const std::string& slurl)
// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
// are collectively optional
// are optional
+
mRegion = LLURI::unescape(path_array[0].asString());
+
+ if(LLStringUtil::containsNonprintable(mRegion))
+ {
+ LLStringUtil::stripNonprintable(mRegion);
+ }
+
path_array.erase(0);
// parse the x, y, and optionally z
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 8fb3340db0..b9e2e11bfa 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -195,7 +195,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail
// Stop shining animation.
mShineAnimTimer.stop();
mSnapshotDelayTimer.start();
- mSnapshotDelayTimer.setTimerExpirySec(delay);
+ mSnapshotDelayTimer.resetWithExpiry(delay);
+
mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
@@ -670,10 +671,27 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return FALSE;
}
- // If we're in freeze-frame mode and camera has moved, update snapshot.
+ if (previewp->mSnapshotDelayTimer.getStarted()) // Wait for a snapshot delay timer
+ {
+ if (!previewp->mSnapshotDelayTimer.hasExpired())
+ {
+ return FALSE;
+ }
+ previewp->mSnapshotDelayTimer.stop();
+ }
+
+ if (LLToolCamera::getInstance()->hasMouseCapture()) // Hide full-screen preview while camming, either don't take snapshots while ALT-zoom active
+ {
+ previewp->setVisible(FALSE);
+ return FALSE;
+ }
+
+ // If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot.
LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
- if (previewp->mForceUpdateSnapshot || (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview &&
+ if (previewp->mForceUpdateSnapshot ||
+ (((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) ||
+ (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) &&
(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)))
{
previewp->mCameraPos = new_camera_pos;
@@ -688,11 +706,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mForceUpdateSnapshot = FALSE;
}
- // see if it's time yet to snap the shot and bomb out otherwise.
- previewp->mSnapshotActive =
- (previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired())
- && !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
- if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
+ if (previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
{
return FALSE;
}
@@ -706,6 +720,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mPreviewImage = new LLImageRaw;
}
+ previewp->mSnapshotActive = TRUE;
+
previewp->setVisible(FALSE);
previewp->setEnabled(FALSE);
@@ -734,40 +750,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
// Full size preview is set: get the decoded image result and save it for animation
if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview)
{
- // Get the decoded version of the formatted image
- previewp->getEncodedImage();
-
- // We need to scale that a bit for display...
- LLPointer<LLImageRaw> scaled = new LLImageRaw(
- previewp->mPreviewImageEncoded->getData(),
- previewp->mPreviewImageEncoded->getWidth(),
- previewp->mPreviewImageEncoded->getHeight(),
- previewp->mPreviewImageEncoded->getComponents());
-
- if (!scaled->isBufferInvalid())
- {
- // leave original image dimensions, just scale up texture buffer
- if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
- {
- // go ahead and shrink image to appropriate power of 2 for display
- scaled->biasedScaleToPowerOfTwo(1024);
- previewp->setImageScaled(TRUE);
- }
- else
- {
- // expand image but keep original image data intact
- scaled->expandToPowerOfTwo(1024, FALSE);
- }
-
- previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
- LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
- gGL.getTexUnit(0)->bind(curr_preview_image);
- curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
- curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
- }
+ previewp->prepareFreezeFrame();
}
+
// The snapshot is updated now...
previewp->mSnapshotUpToDate = TRUE;
@@ -777,7 +762,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
previewp->getWindow()->decBusyCount();
previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode
- previewp->mSnapshotDelayTimer.stop();
previewp->mSnapshotActive = FALSE;
LL_DEBUGS() << "done creating snapshot" << LL_ENDL;
}
@@ -796,6 +780,47 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return TRUE;
}
+void LLSnapshotLivePreview::prepareFreezeFrame()
+{
+ // Get the decoded version of the formatted image
+ getEncodedImage();
+
+ // We need to scale that a bit for display...
+ LLPointer<LLImageRaw> scaled = new LLImageRaw(
+ mPreviewImageEncoded->getData(),
+ mPreviewImageEncoded->getWidth(),
+ mPreviewImageEncoded->getHeight(),
+ mPreviewImageEncoded->getComponents());
+
+ if (!scaled->isBufferInvalid())
+ {
+ // leave original image dimensions, just scale up texture buffer
+ if (mPreviewImageEncoded->getWidth() > 1024 || mPreviewImageEncoded->getHeight() > 1024)
+ {
+ // go ahead and shrink image to appropriate power of 2 for display
+ scaled->biasedScaleToPowerOfTwo(1024);
+ setImageScaled(TRUE);
+ }
+ else
+ {
+ // expand image but keep original image data intact
+ scaled->expandToPowerOfTwo(1024, FALSE);
+ }
+
+ mViewerImage[mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+ LLPointer<LLViewerTexture> curr_preview_image = mViewerImage[mCurImageIndex];
+ gGL.getTexUnit(0)->bind(curr_preview_image);
+ curr_preview_image->setFilteringOption(getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+ curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+
+ if (gSavedSettings.getBOOL("UseFreezeFrame") && mAllowFullScreenPreview)
+ {
+ mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+ }
+ }
+}
+
S32 LLSnapshotLivePreview::getEncodedImageWidth() const
{
S32 width = getWidth();
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index fed33bf37c..57e5d83f8e 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -119,7 +119,7 @@ public:
void generateThumbnailImage(BOOL force_update = FALSE) ;
void resetThumbnailImage() { mThumbnailImage = NULL ; }
void drawPreviewRect(S32 offset_x, S32 offset_y) ;
-
+ void prepareFreezeFrame();
LLViewerTexture* getBigThumbnailImage();
S32 getBigThumbnailWidth() const { return mBigThumbnailWidth ; }
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 3b060d8343..e7971028bf 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -504,21 +504,8 @@ void LLSpeakerMgr::updateSpeakerList()
// For groups, we need to hit the group manager.
// Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id);
- F32 large_group_delay = 0.f;
- if (gdatap)
- {
- //This is a viewer-side bandaid for maint-4414 it does not fix the core issue.
- large_group_delay = (F32)(gdatap->mMemberCount / 5000);
- }
-
- const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay;
-
- if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout))
- {
- // Request the data the first time around
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id);
- }
- else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
+
+ if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
{
// Add group members when we get the complete list (note: can take a while before we get that list)
LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin();
@@ -881,7 +868,7 @@ void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action)
LLUUID sessionId = action["session-id"];
- LLSD result = httpAdapter->postAndYield(httpRequest, url, action, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, action, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 361cc6c48b..e97b73763b 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -46,7 +46,6 @@
#include "llaudioengine_openal.h"
#endif
-#include "llares.h"
#include "llavatarnamecache.h"
#include "llexperiencecache.h"
#include "lllandmark.h"
@@ -112,7 +111,6 @@
#include "llgroupmgr.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
-#include "llhttpclient.h"
#include "llimagebmp.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
@@ -406,9 +404,7 @@ bool idle_startup()
gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
gSavedSettings.setString("LastGPUString", thisGPU);
- // load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
-
+
std::string xml_file = LLUI::locateSkin("xui_version.xml");
LLXMLNodePtr root;
bool xml_ok = false;
@@ -445,13 +441,6 @@ bool idle_startup()
// Load the throttle settings
gViewerThrottle.load();
- if (ll_init_ares() == NULL || !gAres->isInitialized())
- {
- std::string diagnostic = "Could not start address resolution system";
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
//
// Initialize messaging system
//
@@ -737,12 +726,9 @@ bool idle_startup()
if (gLoginMenuBarView == NULL)
{
LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL;
- display_startup();
initialize_edit_menu();
initialize_spellcheck_menu();
- display_startup();
init_menus();
- display_startup();
}
if (show_connect_box)
@@ -754,23 +740,17 @@ bool idle_startup()
if (gUserCredential.isNull())
{
LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL;
- display_startup();
gUserCredential = gLoginHandler.initializeLoginInfo();
- display_startup();
}
// Make sure the process dialog doesn't hide things
- display_startup();
gViewerWindow->setShowProgress(FALSE);
- display_startup();
// Show the login dialog
login_show();
- display_startup();
// connect dialog is already shown, so fill in the names
if (gUserCredential.notNull())
{
LLPanelLogin::setFields( gUserCredential, gRememberPassword);
}
- display_startup();
LLPanelLogin::giveFocus();
// MAINT-3231 Show first run dialog only for Desura viewer
@@ -796,22 +776,15 @@ bool idle_startup()
LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
}
- display_startup();
gViewerWindow->setNormalControlsVisible( FALSE );
- display_startup();
gLoginMenuBarView->setVisible( TRUE );
- display_startup();
gLoginMenuBarView->setEnabled( TRUE );
- display_startup();
show_debug_menus();
- display_startup();
// Hide the splash screen
LLSplashScreen::hide();
- display_startup();
// Push our window frontmost
gViewerWindow->getWindow()->show();
- display_startup();
// DEV-16927. The following code removes errant keystrokes that happen while the window is being
// first made visible.
@@ -819,9 +792,9 @@ bool idle_startup()
MSG msg;
while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) )
{ }
- display_startup();
#endif
- timeout.reset();
+ display_startup();
+ timeout.reset();
return FALSE;
}
@@ -2760,8 +2733,6 @@ void reset_login()
gAgent.cleanup();
LLWorld::getInstance()->destroyClass();
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
-
if ( gViewerWindow )
{ // Hide menus and normal buttons
gViewerWindow->setNormalControlsVisible( FALSE );
@@ -2771,6 +2742,7 @@ void reset_login()
// Hide any other stuff
LLFloaterReg::hideVisibleInstances();
+ LLStartUp::setStartupState( STATE_BROWSER_INIT );
}
//---------------------------------------------------------------------------
@@ -2822,7 +2794,7 @@ void LLStartUp::initNameCache()
void LLStartUp::initExperiences()
{
// Should trigger loading the cache.
- LLExperienceCache::getInstance()->setCapabilityQuery(
+ LLExperienceCache::instance().setCapabilityQuery(
boost::bind(&LLAgent::getRegionCapability, &gAgent, _1));
LLExperienceLog::instance().initialize();
@@ -3223,6 +3195,23 @@ bool process_login_success_response()
LLStringUtil::trim(gDisplayName);
}
}
+ std::string first_name;
+ if(response.has("first_name"))
+ {
+ first_name = response["first_name"].asString();
+ LLStringUtil::replaceChar(first_name, '"', ' ');
+ LLStringUtil::trim(first_name);
+ gAgentUsername = first_name;
+ }
+
+ if(response.has("last_name") && !gAgentUsername.empty() && (gAgentUsername != "Resident"))
+ {
+ std::string last_name = response["last_name"].asString();
+ LLStringUtil::replaceChar(last_name, '"', ' ');
+ LLStringUtil::trim(last_name);
+ gAgentUsername = gAgentUsername + " " + last_name;
+ }
+
if(gDisplayName.empty())
{
if(response.has("first_name"))
@@ -3243,6 +3232,7 @@ bool process_login_success_response()
gDisplayName += text;
}
}
+
if(gDisplayName.empty())
{
gDisplayName.assign(gUserCredential->asString());
diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp
index 7f286044d6..9e54c521b5 100644
--- a/indra/newview/llsyntaxid.cpp
+++ b/indra/newview/llsyntaxid.cpp
@@ -129,7 +129,7 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec)
return;
}
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 8babb874f8..8f64cff47c 100755
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -296,158 +296,6 @@ BOOL LLIMWellWindow::ObjectRowPanel::handleRightMouseDown(S32 x, S32 y, MASK mas
}
/************************************************************************/
-/* LLNotificationWellWindow implementation */
-/************************************************************************/
-
-//////////////////////////////////////////////////////////////////////////
-// PUBLIC METHODS
-LLNotificationWellWindow::WellNotificationChannel::WellNotificationChannel(LLNotificationWellWindow* well_window)
-: LLNotificationChannel(LLNotificationChannel::Params().name(well_window->getPathname())),
- mWellWindow(well_window)
-{
- connectToChannel("Notifications");
- connectToChannel("Group Notifications");
- connectToChannel("Offer");
-}
-
-LLNotificationWellWindow::LLNotificationWellWindow(const LLSD& key)
-: LLSysWellWindow(key)
-{
- mNotificationUpdates.reset(new WellNotificationChannel(this));
-}
-
-// static
-LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
-{
- return LLFloaterReg::getTypedInstance<LLNotificationWellWindow>("notification_well_window", key);
-}
-
-// virtual
-BOOL LLNotificationWellWindow::postBuild()
-{
- BOOL rv = LLSysWellWindow::postBuild();
- setTitle(getString("title_notification_well_window"));
- return rv;
-}
-
-// virtual
-void LLNotificationWellWindow::setVisible(BOOL visible)
-{
- if (visible)
- {
- // when Notification channel is cleared, storable toasts will be added into the list.
- clearScreenChannels();
- }
-
- LLSysWellWindow::setVisible(visible);
-}
-
-//---------------------------------------------------------------------------------
-void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
-{
- LLSD value = p.notification_id;
- // do not add clones
- if( mMessageList->getItemByValue(value))
- return;
-
- LLSysWellItem* new_item = new LLSysWellItem(p);
- if (mMessageList->addItem(new_item, value, ADD_TOP))
- {
- mSysWellChiclet->updateWidget(isWindowEmpty());
- reshapeWindow();
- new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
- new_item->setOnItemClickCallback(boost::bind(&LLNotificationWellWindow::onItemClick, this, _1));
- }
- else
- {
- LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
- << ", title: " << p.title
- << LL_ENDL;
-
- new_item->die();
- }
-}
-
-void LLNotificationWellWindow::closeAll()
-{
- // Need to clear notification channel, to add storable toasts into the list.
- clearScreenChannels();
- std::vector<LLPanel*> items;
- mMessageList->getItems(items);
- for (std::vector<LLPanel*>::iterator
- iter = items.begin(),
- iter_end = items.end();
- iter != iter_end; ++iter)
- {
- LLSysWellItem* sys_well_item = dynamic_cast<LLSysWellItem*>(*iter);
- if (sys_well_item)
- onItemClose(sys_well_item);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-// PRIVATE METHODS
-void LLNotificationWellWindow::initChannel()
-{
- LLSysWellWindow::initChannel();
- if(mChannel)
- {
- mChannel->addOnStoreToastCallback(boost::bind(&LLNotificationWellWindow::onStoreToast, this, _1, _2));
- }
-}
-
-void LLNotificationWellWindow::clearScreenChannels()
-{
- // 1 - remove StartUp toast and channel if present
- if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
- {
- LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
- }
-
- // 2 - remove toasts in Notification channel
- if(mChannel)
- {
- mChannel->removeAndStoreAllStorableToasts();
- }
-}
-
-void LLNotificationWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id)
-{
- LLSysWellItem::Params p;
- p.notification_id = id;
- p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
- addItem(p);
-}
-
-void LLNotificationWellWindow::onItemClick(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
- LLFloaterReg::showInstance("inspect_toast", id);
-}
-
-void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
-
- if(mChannel)
- {
- // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
- mChannel->killToastByNotificationID(id);
- }
- else
- {
- // removeItemByID() should be called one time for each item to remove it from notification well
- removeItemByID(id);
- }
-
-}
-
-void LLNotificationWellWindow::onAdd( LLNotificationPtr notify )
-{
- removeItemByID(notify->getID());
-}
-
-/************************************************************************/
/* LLIMWellWindow implementation */
/************************************************************************/
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 71b41476f5..d02293e6ff 100755
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -96,57 +96,6 @@ protected:
};
/**
- * Class intended to manage incoming notifications.
- *
- * It contains a list of notifications that have not been responded to.
- */
-class LLNotificationWellWindow : public LLSysWellWindow
-{
-public:
- LLNotificationWellWindow(const LLSD& key);
- static LLNotificationWellWindow* getInstance(const LLSD& key = LLSD());
-
- /*virtual*/ BOOL postBuild();
- /*virtual*/ void setVisible(BOOL visible);
- /*virtual*/ void onAdd(LLNotificationPtr notify);
- // Operating with items
- void addItem(LLSysWellItem::Params p);
-
- // Closes all notifications and removes them from the Notification Well
- void closeAll();
-
-protected:
- struct WellNotificationChannel : public LLNotificationChannel
- {
- WellNotificationChannel(LLNotificationWellWindow*);
- void onDelete(LLNotificationPtr notify)
- {
- mWellWindow->removeItemByID(notify->getID());
- }
-
- LLNotificationWellWindow* mWellWindow;
- };
-
- LLNotificationChannelPtr mNotificationUpdates;
- /*virtual*/ const std::string& getAnchorViewName() { return NOTIFICATION_WELL_ANCHOR_NAME; }
-
-private:
- // init Window's channel
- void initChannel();
- void clearScreenChannels();
-
- void onStoreToast(LLPanel* info_panel, LLUUID id);
-
- // Handlers
- void onItemClick(LLSysWellItem* item);
- void onItemClose(LLSysWellItem* item);
-
- // ID of a toast loaded by user (by clicking notification well item)
- LLUUID mLoadedToastId;
-
-};
-
-/**
* Class intended to manage incoming messages in IM chats.
*
* It contains a list list of all active IM sessions.
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index ef852bc905..bcdf8360ed 100755
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1544,17 +1544,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
{
std::string dirname = mTexturesDirName + delem + subdirs[i];
LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL;
- gDirUtilp->deleteFilesInDir(dirname, mask);
if (purge_directories)
{
- LLFile::rmdir(dirname);
+ gDirUtilp->deleteDirAndContents(dirname);
+ }
+ else
+ {
+ gDirUtilp->deleteFilesInDir(dirname, mask);
}
}
if (purge_directories)
{
gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
LLFile::rmdir(mTexturesDirName);
- }
+ }
}
mHeaderIDMap.clear();
mTexturesSizeMap.clear();
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 30d90431ea..1f966dc76f 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -254,6 +254,20 @@ static const S32 HTTP_NONPIPE_REQUESTS_LOW_WATER = 20;
static const S32 HTTP_REQUESTS_RANGE_END_MAX = 20000000;
//////////////////////////////////////////////////////////////////////////////
+namespace
+{
+ // The NoOpDeletor is used when passing certain objects (the LLTextureFetchWorker and
+ // the LLTextureFetchDebugger) in a smart pointer below for passage into
+ // the LLCore::Http libararies. When the smart pointer is destroyed, no
+ // action will be taken since we do not in these cases want the object to
+ // be destroyed at the end of the call.
+ //
+ // *NOTE$: Yes! It is "Deletor"
+ // http://english.stackexchange.com/questions/4733/what-s-the-rule-for-adding-er-vs-or-when-nouning-a-verb
+ // "delete" derives from Latin "deletus"
+ void NoOpDeletor(LLCore::HttpHandler *)
+ { /*NoOp*/ }
+}
static const char* e_state_name[] =
{
@@ -806,16 +820,10 @@ public:
* ownership of the copy and disposes of it
* when done.
*/
- TFReqSendMetrics(const std::string & caps_url,
- const LLUUID & session_id,
- const LLUUID & agent_id,
- LLViewerAssetStats * main_stats)
- : LLTextureFetch::TFRequest(),
- mCapsURL(caps_url),
- mSessionID(session_id),
- mAgentID(agent_id),
- mMainStats(main_stats)
- {}
+ TFReqSendMetrics(const std::string & caps_url,
+ const LLUUID & session_id,
+ const LLUUID & agent_id,
+ LLViewerAssetStats * main_stats);
TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
virtual ~TFReqSendMetrics();
@@ -827,6 +835,9 @@ public:
const LLUUID mSessionID;
const LLUUID mAgentID;
LLViewerAssetStats * mMainStats;
+
+private:
+ LLCore::HttpHandler::ptr_t mHandler;
};
/*
@@ -965,7 +976,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
if (mHttpActive)
{
// Issue a cancel on a live request...
- mFetcher->getHttpRequest().requestCancel(mHttpHandle, NULL);
+ mFetcher->getHttpRequest().requestCancel(mHttpHandle, LLCore::HttpHandler::ptr_t());
}
if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
{
@@ -1569,7 +1580,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
mUrl,
options,
mFetcher->mHttpHeaders,
- this);
+ LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
}
else
{
@@ -1582,7 +1593,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
: mRequestedSize,
options,
mFetcher->mHttpHeaders,
- this);
+ LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
}
if (LLCORE_HTTP_HANDLE_INVALID == mHttpHandle)
{
@@ -3937,9 +3948,6 @@ public:
}
}; // end class AssetReportHandler
-AssetReportHandler stats_handler;
-
-
/**
* Implements the 'Set Region' command.
*
@@ -3953,6 +3961,18 @@ TFReqSetRegion::doWork(LLTextureFetch *)
return true;
}
+TFReqSendMetrics::TFReqSendMetrics(const std::string & caps_url,
+ const LLUUID & session_id,
+ const LLUUID & agent_id,
+ LLViewerAssetStats * main_stats):
+ LLTextureFetch::TFRequest(),
+ mCapsURL(caps_url),
+ mSessionID(session_id),
+ mAgentID(agent_id),
+ mMainStats(main_stats),
+ mHandler(new AssetReportHandler)
+{}
+
TFReqSendMetrics::~TFReqSendMetrics()
{
@@ -3971,7 +3991,6 @@ bool
TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
{
static const U32 report_priority(1);
- static LLCore::HttpHandler * const handler(fetcher->isQAMode() || true ? &stats_handler : NULL);
//if (! gViewerAssetStatsThread1)
// return true;
@@ -4021,7 +4040,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
sd,
LLCore::HttpOptions::ptr_t(),
fetcher->getMetricsHeaders(),
- handler);
+ mHandler);
LLTextureFetch::svMetricsDataBreak = false;
}
else
@@ -4598,7 +4617,7 @@ S32 LLTextureFetchDebugger::fillCurlQueue()
requestedSize,
LLCore::HttpOptions::ptr_t(),
mHttpHeaders,
- this);
+ LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
if (LLCORE_HTTP_HANDLE_INVALID != handle)
{
mHandleToFetchIndex[handle] = i;
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index e569175e8f..50233eee5e 100755
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -37,7 +37,6 @@
#include "lltextureinfo.h"
#include "llapr.h"
#include "llimageworker.h"
-#include "llcurl.h"
#include "httprequest.h"
#include "httpoptions.h"
#include "httpheaders.h"
diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp
index ca42d710f8..8ded148e17 100755
--- a/indra/newview/lltexturestats.cpp
+++ b/indra/newview/lltexturestats.cpp
@@ -30,8 +30,8 @@
#include "llagent.h"
#include "lltexturefetch.h"
#include "lltexturestats.h"
-#include "lltexturestatsuploader.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
void send_texture_stats_to_sim(const LLSD &texture_stats)
{
@@ -49,6 +49,16 @@ void send_texture_stats_to_sim(const LLSD &texture_stats)
std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats");
LL_INFOS() << "uploading texture stats data to simulator" << LL_ENDL;
- LLTextureStatsUploader::uploadStatsToSimulator(texture_cap_url, texture_stats);
+
+ if (texture_cap_url != "")
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(texture_cap_url, texture_stats,
+ "Texture statistics posted to sim.", "Error posting texture statistics to sim");
+ }
+ else
+ {
+ LL_INFOS() << "Not sending texture stats: " << texture_stats
+ << " as there is no cap url." << LL_ENDL;
+ }
}
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index e00b18dedb..e22f527a65 100755
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -92,7 +92,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
+LLTrans::getString("UTCTimeSec")+"] ["
+LLTrans::getString("UTCTimeTimezone")+"]";
const LLDate timeStamp = notification->getDate();
- LLDate notice_date = timeStamp.notNull() ? timeStamp : LLDate::now();
+ LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate();
LLSD substitution;
substitution["datetime"] = (S32) notice_date.secondsSinceEpoch();
LLStringUtil::format(timeStr, substitution);
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 81fbc471b3..05c98826d2 100755
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -821,21 +821,6 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
if (!handled)
{
- // *TODO: Suppress the "outbox" case once "marketplace" is used everywhere for everyone
- // Disallow drag and drop to 3D from the outbox
- const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- if (outbox_id.notNull())
- {
- for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
- {
- if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id))
- {
- *acceptance = ACCEPT_NO;
- mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld");
- return;
- }
- }
- }
// Disallow drag and drop to 3D from the marketplace
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
if (marketplacelistings_id.notNull())
@@ -1155,8 +1140,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
}
LLSculptParams sculpt_params;
- sculpt_params.setSculptTexture(asset_id);
- sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
+ sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH);
hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
dialog_refresh_all();
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index c0ba0a1f39..1936e24761 100755
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -35,31 +35,257 @@
#include "llui.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
-
+#include "llcoros.h"
#include "reader.h"
+#include "llcorehttputil.h"
+
+
+/**
+* Handler of an HTTP machine translation service.
+*
+* Derived classes know the service URL
+* and how to parse the translation result.
+*/
+class LLTranslationAPIHandler
+{
+public:
+ typedef std::pair<std::string, std::string> LanguagePair_t;
+
+ /**
+ * Get URL for translation of the given string.
+ *
+ * Sending HTTP GET request to the URL will initiate translation.
+ *
+ * @param[out] url Place holder for the result.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param text Text to translate.
+ */
+ virtual std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const = 0;
+
+ /**
+ * Get URL to verify the given API key.
+ *
+ * Sending request to the URL verifies the key.
+ * Positive HTTP response (code 200) means that the key is valid.
+ *
+ * @param[out] url Place holder for the URL.
+ * @param[in] key Key to verify.
+ */
+ virtual std::string getKeyVerificationURL(
+ const std::string &key) const = 0;
+
+ /**
+ * Parse translation response.
+ *
+ * @param[in,out] status HTTP status. May be modified while parsing.
+ * @param body Response text.
+ * @param[out] translation Translated text.
+ * @param[out] detected_lang Detected source language. May be empty.
+ * @param[out] err_msg Error message (in case of error).
+ */
+ virtual bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const = 0;
+
+ /**
+ * @return if the handler is configured to function properly
+ */
+ virtual bool isConfigured() const = 0;
+
+ virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
+ virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+
+
+ virtual ~LLTranslationAPIHandler() {}
+
+ void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc);
+ void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+};
+
+void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
+{
+ LLCoros::instance().launch("Translation", boost::bind(&LLTranslationAPIHandler::translateMessageCoro,
+ this, fromTo, msg, success, failure));
+
+}
+
+
+void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+ httpOpts->setFollowRedirects(true);
+
+ std::string url = this->getKeyVerificationURL(key);
+ if (url.empty())
+ {
+ LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
+ return;
+ }
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool bOk = true;
+ if (!status)
+ bOk = false;
+
+ if (!fnc.empty())
+ fnc(service, bOk);
+}
+
+void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg,
+ LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+ std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg);
+ if (url.empty())
+ {
+ LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
+ return;
+ }
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ std::string translation, err_msg;
+ std::string detected_lang(fromTo.second);
+
+ int parseResult = status.getType();
+ const LLSD::Binary &rawBody = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
+ std::string body(rawBody.begin(), rawBody.end());
+
+ if (this->parseResponse(parseResult, body, translation, detected_lang, err_msg))
+ {
+ // Fix up the response
+ LLStringUtil::replaceString(translation, "&lt;", "<");
+ LLStringUtil::replaceString(translation, "&gt;", ">");
+ LLStringUtil::replaceString(translation, "&quot;", "\"");
+ LLStringUtil::replaceString(translation, "&#39;", "'");
+ LLStringUtil::replaceString(translation, "&amp;", "&");
+ LLStringUtil::replaceString(translation, "&apos;", "'");
+
+ if (!success.empty())
+ success(translation, detected_lang);
+ }
+ else
+ {
+ if (err_msg.empty())
+ {
+ err_msg = LLTrans::getString("TranslationResponseParseError");
+ }
+
+ LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL;
+ if (!failure.empty())
+ failure(status, err_msg);
+ }
+
+
+}
+
+//=========================================================================
+/// Google Translate v2 API handler.
+class LLGoogleTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLGoogleTranslationHandler);
+
+public:
+ /*virtual*/ std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ std::string getKeyVerificationURL(
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+
+ /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+
+private:
+ static void parseErrorResponse(
+ const Json::Value& root,
+ int& status,
+ std::string& err_msg);
+ static bool parseTranslation(
+ const Json::Value& root,
+ std::string& translation,
+ std::string& detected_lang);
+ static std::string getAPIKey();
+
+};
+
+//-------------------------------------------------------------------------
// virtual
-void LLGoogleTranslationHandler::getTranslateURL(
- std::string &url,
+std::string LLGoogleTranslationHandler::getTranslateURL(
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
- url = std::string("https://www.googleapis.com/language/translate/v2?key=")
+ std::string url = std::string("https://www.googleapis.com/language/translate/v2?key=")
+ getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang;
if (!from_lang.empty())
{
url += "&source=" + from_lang;
}
+ return url;
}
// virtual
-void LLGoogleTranslationHandler::getKeyVerificationURL(
- std::string& url,
+std::string LLGoogleTranslationHandler::getKeyVerificationURL(
const std::string& key) const
{
- url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+ std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+ key + "&target=en";
+ return url;
}
// virtual
@@ -154,28 +380,66 @@ std::string LLGoogleTranslationHandler::getAPIKey()
return gSavedSettings.getString("GoogleTranslateAPIKey");
}
+/*virtual*/
+void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+ LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+ this, LLTranslate::SERVICE_GOOGLE, key, fnc));
+}
+
+
+//=========================================================================
+/// Microsoft Translator v2 API handler.
+class LLBingTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLBingTranslationHandler);
+
+public:
+ /*virtual*/ std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ std::string getKeyVerificationURL(
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+
+ /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+private:
+ static std::string getAPIKey();
+ static std::string getAPILanguageCode(const std::string& lang);
+
+};
+
+//-------------------------------------------------------------------------
// virtual
-void LLBingTranslationHandler::getTranslateURL(
- std::string &url,
+std::string LLBingTranslationHandler::getTranslateURL(
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
+ std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
+ getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang);
if (!from_lang.empty())
{
url += "&from=" + getAPILanguageCode(from_lang);
}
+ return url;
}
+
// virtual
-void LLBingTranslationHandler::getKeyVerificationURL(
- std::string& url,
+std::string LLBingTranslationHandler::getKeyVerificationURL(
const std::string& key) const
{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
+ std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
+ key;
+ return url;
}
// virtual
@@ -242,96 +506,31 @@ std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang
return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
}
-LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
-: mFromLang(from_lang)
-, mToLang(to_lang)
-, mHandler(LLTranslate::getPreferredHandler())
+/*virtual*/
+void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
{
+ LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+ this, LLTranslate::SERVICE_BING, key, fnc));
}
-// virtual
-void LLTranslate::TranslationReceiver::completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+//=========================================================================
+/*static*/
+void LLTranslate::translateMessage(const std::string &from_lang, const std::string &to_lang,
+ const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure)
{
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
-
- const std::string body = strstrm.str();
- std::string translation, detected_lang, err_msg;
- int status = getStatus();
- LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;
- LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
- if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
- {
- // Fix up the response
- LLStringUtil::replaceString(translation, "&lt;", "<");
- LLStringUtil::replaceString(translation, "&gt;",">");
- LLStringUtil::replaceString(translation, "&quot;","\"");
- LLStringUtil::replaceString(translation, "&#39;","'");
- LLStringUtil::replaceString(translation, "&amp;","&");
- LLStringUtil::replaceString(translation, "&apos;","'");
-
- handleResponse(translation, detected_lang);
- }
- else
- {
- if (err_msg.empty())
- {
- err_msg = LLTrans::getString("TranslationResponseParseError");
- }
+ LLTranslationAPIHandler& handler = getPreferredHandler();
- LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL;
- handleFailure(status, err_msg);
- }
+ handler.translateMessage(LLTranslationAPIHandler::LanguagePair_t(from_lang, to_lang), mesg, success, failure);
}
-LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
-: mService(service)
+/*static*/
+void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc)
{
-}
+ LLTranslationAPIHandler& handler = getHandler(service);
-LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
-{
- return mService;
+ handler.verifyKey(key, fnc);
}
-// virtual
-void LLTranslate::KeyVerificationReceiver::completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- bool ok = (getStatus() == HTTP_OK);
- setVerificationStatus(ok);
-}
-
-//static
-void LLTranslate::translateMessage(
- TranslationReceiverPtr &receiver,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &mesg)
-{
- std::string url;
- receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
-
- LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
- sendRequest(url, receiver);
-}
-
-// static
-void LLTranslate::verifyKey(
- KeyVerificationReceiverPtr& receiver,
- const std::string& key)
-{
- std::string url;
- const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
- handler.getKeyVerificationURL(url, key);
-
- LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
- sendRequest(url, receiver);
-}
//static
std::string LLTranslate::getTranslateLanguage()
@@ -352,7 +551,7 @@ bool LLTranslate::isTranslationConfigured()
}
// static
-const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
+LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
{
EService service = SERVICE_BING;
@@ -366,7 +565,7 @@ const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
}
// static
-const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
+LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
{
static LLGoogleTranslationHandler google;
static LLBingTranslationHandler bing;
@@ -378,25 +577,3 @@ const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
return bing;
}
-
-// static
-void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
-{
- static const float REQUEST_TIMEOUT = 5;
- static LLSD sHeader;
-
- if (!sHeader.size())
- {
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LLVersionInfo::getChannel().c_str(),
- LLVersionInfo::getMajor(),
- LLVersionInfo::getMinor(),
- LLVersionInfo::getPatch(),
- LLVersionInfo::getBuild());
-
- sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
- sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent);
- }
-
- LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT);
-}
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 972274714a..bf431cdfbb 100755
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -27,136 +27,15 @@
#ifndef LL_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
-#include "llhttpclient.h"
#include "llbufferstream.h"
+#include <boost/function.hpp>
namespace Json
{
class Value;
}
-/**
- * Handler of an HTTP machine translation service.
- *
- * Derived classes know the service URL
- * and how to parse the translation result.
- */
-class LLTranslationAPIHandler
-{
-public:
- /**
- * Get URL for translation of the given string.
- *
- * Sending HTTP GET request to the URL will initiate translation.
- *
- * @param[out] url Place holder for the result.
- * @param from_lang Source language. Leave empty for auto-detection.
- * @param to_lang Target language.
- * @param text Text to translate.
- */
- virtual void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const = 0;
-
- /**
- * Get URL to verify the given API key.
- *
- * Sending request to the URL verifies the key.
- * Positive HTTP response (code 200) means that the key is valid.
- *
- * @param[out] url Place holder for the URL.
- * @param[in] key Key to verify.
- */
- virtual void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const = 0;
-
- /**
- * Parse translation response.
- *
- * @param[in,out] status HTTP status. May be modified while parsing.
- * @param body Response text.
- * @param[out] translation Translated text.
- * @param[out] detected_lang Detected source language. May be empty.
- * @param[out] err_msg Error message (in case of error).
- */
- virtual bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const = 0;
-
- /**
- * @return if the handler is configured to function properly
- */
- virtual bool isConfigured() const = 0;
-
- virtual ~LLTranslationAPIHandler() {}
-};
-
-/// Google Translate v2 API handler.
-class LLGoogleTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLGoogleTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-
-private:
- static void parseErrorResponse(
- const Json::Value& root,
- int& status,
- std::string& err_msg);
- static bool parseTranslation(
- const Json::Value& root,
- std::string& translation,
- std::string& detected_lang);
- static std::string getAPIKey();
-};
-
-/// Microsoft Translator v2 API handler.
-class LLBingTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLBingTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-private:
- static std::string getAPIKey();
- static std::string getAPILanguageCode(const std::string& lang);
-};
-
+class LLTranslationAPIHandler;
/**
* Entry point for machine translation services.
*
@@ -180,84 +59,9 @@ public :
SERVICE_GOOGLE,
} EService;
- /**
- * Subclasses are supposed to handle translation results (e.g. show them in chat)
- */
- class TranslationReceiver: public LLHTTPClient::Responder
- {
- public:
-
- /**
- * Using mHandler, parse incoming response.
- *
- * Calls either handleResponse() or handleFailure()
- * depending on the HTTP status code and parsing success.
- *
- * @see handleResponse()
- * @see handleFailure()
- * @see mHandler
- */
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- protected:
- friend class LLTranslate;
-
- /// Remember source and target languages for subclasses to be able to filter inappropriate results.
- TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
-
- /// Override point to handle successful translation.
- virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
-
- /// Override point to handle unsuccessful translation.
- virtual void handleFailure(int status, const std::string& err_msg) = 0;
-
- std::string mFromLang;
- std::string mToLang;
- const LLTranslationAPIHandler& mHandler;
- };
-
- /**
- * Subclasses are supposed to handle API key verification result.
- */
- class KeyVerificationReceiver: public LLHTTPClient::Responder
- {
- public:
- EService getService() const;
-
- protected:
- /**
- * Save the translation service the key belongs to.
- *
- * Subclasses need to know it.
- *
- * @see getService()
- */
- KeyVerificationReceiver(EService service);
-
- /**
- * Parse verification response.
- *
- * Calls setVerificationStatus() with the verification status,
- * which is true if HTTP status code is 200.
- *
- * @see setVerificationStatus()
- */
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- /**
- * Override point for subclasses to handle key verification status.
- */
- virtual void setVerificationStatus(bool ok) = 0;
-
- EService mService;
- };
-
- typedef LLPointer<TranslationReceiver> TranslationReceiverPtr;
- typedef LLPointer<KeyVerificationReceiver> KeyVerificationReceiverPtr;
+ typedef boost::function<void(EService, bool)> KeyVerificationResult_fn;
+ typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn;
+ typedef boost::function<void(int, std::string)> TranslationFailure_fn;
/**
* Translate given text.
@@ -267,15 +71,15 @@ public :
* @param to_lang Target language.
* @param mesg Text to translate.
*/
- static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
+ static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure);
- /**
+ /**
* Verify given API key of a translation service.
*
* @param receiver Object to pass verification result to.
* @param key Key to verify.
*/
- static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
+ static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc);
/**
* @return translation target language
@@ -288,9 +92,8 @@ public :
static bool isTranslationConfigured();
private:
- static const LLTranslationAPIHandler& getPreferredHandler();
- static const LLTranslationAPIHandler& getHandler(EService service);
- static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
+ static LLTranslationAPIHandler& getPreferredHandler();
+ static LLTranslationAPIHandler& getHandler(EService service);
};
#endif
diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp
index c6a0a15759..9b7c13b57d 100644
--- a/indra/newview/lltwitterconnect.cpp
+++ b/indra/newview/lltwitterconnect.cpp
@@ -84,9 +84,7 @@ void LLTwitterConnect::twitterConnectCoro(std::string requestToken, std::string
if (!oauthVerifier.empty())
body["oauth_verifier"] = oauthVerifier;
- setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
-
- LLSD result = httpAdapter->putAndYield(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts);
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -168,9 +166,7 @@ void LLTwitterConnect::twitterShareCoro(std::string route, LLSD share)
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- setConnectionState(LLTwitterConnect::TWITTER_POSTING);
-
- LLSD result = httpAdapter->postAndYield(httpRequest, getTwitterConnectURL(route, true), share, httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL(route, true), share, httpOpts);
if (testShareStatus(result))
{
@@ -235,7 +231,7 @@ void LLTwitterConnect::twitterShareImageCoro(LLPointer<LLImageFormatted> image,
body << "\r\n--" << boundary << "--\r\n";
- LLSD result = httpAdapter->postAndYield(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
if (testShareStatus(result))
{
@@ -257,9 +253,7 @@ void LLTwitterConnect::twitterDisconnectCoro()
httpOpts->setFollowRedirects(false);
- setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
-
- LLSD result = httpAdapter->deleteAndYield(httpRequest, getTwitterConnectURL("/connection"), httpOpts);
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getTwitterConnectURL("/connection"), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -293,7 +287,7 @@ void LLTwitterConnect::twitterConnectedCoro(bool autoConnect)
httpOpts->setFollowRedirects(false);
setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
- LLSD result = httpAdapter->getAndYield(httpRequest, getTwitterConnectURL("/connection", true), httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/connection", true), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -342,7 +336,7 @@ void LLTwitterConnect::twitterInfoCoro()
httpOpts->setWantHeaders(true);
httpOpts->setFollowRedirects(false);
- LLSD result = httpAdapter->getAndYield(httpRequest, getTwitterConnectURL("/info", true), httpOpts);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/info", true), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -424,12 +418,16 @@ std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, boo
void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier)
{
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+
LLCoros::instance().launch("LLTwitterConnect::twitterConnectCoro",
boost::bind(&LLTwitterConnect::twitterConnectCoro, this, request_token, oauth_verifier));
}
void LLTwitterConnect::disconnectFromTwitter()
{
+ setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
+
LLCoros::instance().launch("LLTwitterConnect::twitterDisconnectCoro",
boost::bind(&LLTwitterConnect::twitterDisconnectCoro, this));
}
@@ -455,12 +453,16 @@ void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::stri
body["image"] = image_url;
body["status"] = status;
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+
LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro",
boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/photo", body));
}
void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status)
{
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+
LLCoros::instance().launch("LLTwitterConnect::twitterShareImageCoro",
boost::bind(&LLTwitterConnect::twitterShareImageCoro, this, image, status));
}
@@ -470,6 +472,8 @@ void LLTwitterConnect::updateStatus(const std::string& status)
LLSD body;
body["status"] = status;
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+
LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro",
boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/status", body));
}
diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h
index 02baf8f1c0..15c3dad38e 100755
--- a/indra/newview/lluploadfloaterobservers.h
+++ b/indra/newview/lluploadfloaterobservers.h
@@ -28,7 +28,6 @@
#define LL_LLUPLOADFLOATEROBSERVERS_H
#include "llfloater.h"
-#include "llhttpclient.h"
#include "llhandle.h"
class LLUploadPermissionsObserver
diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp
index cad5769042..8a61114852 100755
--- a/indra/newview/llurllineeditorctrl.cpp
+++ b/indra/newview/llurllineeditorctrl.cpp
@@ -84,7 +84,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()
const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));
LLWString text_to_copy;
// *HACK: Because LLSLURL is currently broken we cannot use it to check if unescaped_text is a valid SLURL (see EXT-8335).
- if (LLStringUtil::startsWith(unescaped_text, "http://")) // SLURL
+ if (LLStringUtil::startsWith(unescaped_text, "http://") || LLStringUtil::startsWith(unescaped_text, "secondlife://")) // SLURL
text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));
else // human-readable location
text_to_copy = utf8str_to_wstring(unescaped_text);
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 6c6d3a4f33..f0dafec240 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -174,7 +174,7 @@ S32 LLResourceUploadInfo::getEconomyUploadCost()
getAssetType() == LLAssetType::AT_ANIMATION ||
getAssetType() == LLAssetType::AT_MESH)
{
- return LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ return LLGlobalEconomy::Singleton::instance().getPriceUpload();
}
return 0;
@@ -666,7 +666,7 @@ LLUUID LLViewerAssetUpload::EnqueueInventoryUpload(const std::string &url, const
{
std::string procName("LLViewerAssetUpload::AssetInventoryUploadCoproc(");
- LLUUID queueId = LLCoprocedureManager::getInstance()->enqueueCoprocedure("Upload",
+ LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("Upload",
procName + LLAssetType::lookup(uploadInfo->getAssetType()) + ")",
boost::bind(&LLViewerAssetUpload::AssetInventoryUploadCoproc, _1, _2, url, uploadInfo));
@@ -689,7 +689,7 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti
return;
}
- llcoro::yield();
+ llcoro::suspend();
if (uploadInfo->showUploadDialog())
{
@@ -700,7 +700,7 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti
LLSD body = uploadInfo->generatePostBody();
- result = httpAdapter->postAndYield(httpRequest, url, body);
+ result = httpAdapter->postAndSuspend(httpRequest, url, body);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -718,11 +718,13 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti
bool success = false;
if (!uploader.empty() && uploadInfo->getAssetId().notNull())
{
- result = httpAdapter->postFileAndYield(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType());
+ result = httpAdapter->postFileAndSuspend(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType());
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (!status)
+ std::string ulstate = result["state"].asString();
+
+ if ((!status) || (ulstate != "complete"))
{
HandleUploadError(status, result, uploadInfo);
if (uploadInfo->showUploadDialog())
@@ -730,7 +732,7 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti
return;
}
- S32 uploadPrice = uploadInfo->getEconomyUploadCost();
+ S32 uploadPrice = result["upload_price"].asInteger();//uploadInfo->getEconomyUploadCost();
if (uploadPrice > 0)
{
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 2bd8e5f99c..c0e5e632e6 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -89,9 +89,9 @@
#include "llfloatermodelpreview.h"
#include "llfloaternamedesc.h"
#include "llfloaternotificationsconsole.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterobjectweights.h"
#include "llfloateropenobject.h"
-#include "llfloateroutbox.h"
#include "llfloaterpathfindingcharacters.h"
#include "llfloaterpathfindingconsole.h"
#include "llfloaterpathfindinglinksets.h"
@@ -266,11 +266,11 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>);
LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>);
- LLFloaterReg::add("notification_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNotificationWellWindow>);
+
+ LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>);
LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
- LLFloaterReg::add("outbox", "floater_merchant_outbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutbox>);
LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);
LLFloaterPayUtil::registerFloater();
diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index 158cacbc81..b8ff2cc9b4 100644
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -137,7 +137,7 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
bool boxes_invisible = !gSavedSettings.getBOOL("InventoryOutboxMakeVisible");
addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Received Items", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
- addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
+ addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, true));
addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "Inv_SysOpen", "Inv_SysClosed", FALSE, true));
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 573791aca3..0ee873d7a1 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -427,7 +427,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const
body["items"][0]["owner_id"] = mPermissions.getOwner();
body["items"][0]["item_id"] = mUUID;
- LLInventoryModel::FetchItemHttpHandler * handler(new LLInventoryModel::FetchItemHttpHandler(body));
+ LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
gInventory.requestPost(true, url, body, handler, "Inventory Item");
}
else
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index f332a4e98e..4e8fa28b86 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1280,7 +1280,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL;
LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL;
- LLSD result = httpAdapter->getRawAndYield(httpRequest, url, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -1347,7 +1347,7 @@ void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidTok
bas << std::noskipws << openidToken;
- LLSD result = httpAdapter->postRawAndYield(httpRequest, openidUrl, rawbody, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->postRawAndSuspend(httpRequest, openidUrl, rawbody, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -2592,6 +2592,9 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ // Increment our refcount so that we do not go away while the coroutine is active.
+ this->ref();
+
mMimeProbe = httpAdapter;
httpOpts->setFollowRedirects(true);
@@ -2600,7 +2603,7 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
httpHeaders->append(HTTP_OUT_HEADER_COOKIE, "");
- LLSD result = httpAdapter->getRawAndYield(httpRequest, url, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
mMimeProbe.reset();
@@ -2612,35 +2615,47 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
LL_WARNS() << "Error retrieving media headers." << LL_ENDL;
}
- LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
-
- const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE].asStringRef();
+ if (this->getNumRefs() > 1)
+ { // if there is only a single ref count outstanding it will be the one we took out above...
+ // we can skip the rest of this routine
- std::string::size_type idx1 = mediaType.find_first_of(";");
- std::string mimeType = mediaType.substr(0, idx1);
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
- // We now no longer need to check the error code returned from the probe.
- // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting.
- // The probe was successful.
- if (mimeType.empty())
- {
- // Some sites don't return any content-type header at all.
- // Treat an empty mime type as text/html.
- mimeType = HTTP_CONTENT_TEXT_HTML;
- }
+ const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE].asStringRef();
- LL_DEBUGS() << "Media type \"" << mediaType << "\", mime type is \"" << mimeType << "\"" << LL_ENDL;
+ std::string::size_type idx1 = mediaType.find_first_of(";");
+ std::string mimeType = mediaType.substr(0, idx1);
- // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
- // Make a local copy so we can call loadURI() afterwards.
+ // We now no longer need to check the error code returned from the probe.
+ // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting.
+ // The probe was successful.
+ if (mimeType.empty())
+ {
+ // Some sites don't return any content-type header at all.
+ // Treat an empty mime type as text/html.
+ mimeType = HTTP_CONTENT_TEXT_HTML;
+ }
- if (!mimeType.empty())
- {
- if (initializeMedia(mimeType))
+ LL_DEBUGS() << "Media type \"" << mediaType << "\", mime type is \"" << mimeType << "\"" << LL_ENDL;
+
+ // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
+ // Make a local copy so we can call loadURI() afterwards.
+
+ if (!mimeType.empty())
{
- loadURI();
+ if (initializeMedia(mimeType))
+ {
+ loadURI();
+ }
}
+
}
+ else
+ {
+ LL_WARNS() << "LLViewerMediaImpl to be released." << LL_ENDL;
+ }
+
+ this->unref();
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -3634,7 +3649,7 @@ void LLViewerMediaImpl::cancelMimeTypeProbe()
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t probeAdapter = mMimeProbe.lock();
if (probeAdapter)
- probeAdapter->cancelYieldingOperation();
+ probeAdapter->cancelSuspendedOperation();
}
void LLViewerMediaImpl::addObject(LLVOVolume* obj)
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 92d644c900..d93eb3d6e0 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -254,6 +254,7 @@ public:
void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;};
void clearCache();
void setPageZoomFactor( double factor );
+ double getPageZoomFactor() {return mZoomFactor;}
std::string getMimeType() { return mMimeType; }
void scaleMouse(S32 *mouse_x, S32 *mouse_y);
void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2505ae6a9c..f32ae27073 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -57,6 +57,7 @@
#include "llfacebookconnect.h"
#include "llfilepicker.h"
#include "llfirstuse.h"
+#include "llfloaterabout.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llbuycurrencyhtml.h"
@@ -390,32 +391,10 @@ void set_underclothes_menu_options()
void set_merchant_SLM_menu()
{
- // DD-170 : SLM Alpha and Beta program : for the moment, we always show the SLM menu and
- // tools so that all merchants can try out the UI, even if not migrated.
- // *TODO : Keep SLM UI hidden for non migrated merchant in released viewer
-
- //if (LLMarketplaceData::instance().getSLMStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT)
- //{
- // Merchant not migrated: show only the old Merchant Outbox menu
- // gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE);
- //}
- //else
- //{
- // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool
- gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE);
- LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
- gToolBarView->enableCommand(command->id(), true);
- //}
-}
-
-void set_merchant_outbox_menu(U32 status, const LLSD& content)
-{
- // If the merchant is fully migrated, the API is disabled (503) and we won't show the old menu item.
- // In all other cases, we show it.
- if (status != MarketplaceErrorCodes::IMPORT_SERVER_API_DISABLED)
- {
- gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE);
- }
+ // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool
+ gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE);
+ LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
+ gToolBarView->enableCommand(command->id(), true);
}
void check_merchant_status()
@@ -434,17 +413,6 @@ void check_merchant_status()
// Launch an SLM test connection to get the merchant status
LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu));
-
- // Do the Merchant Outbox init only once per session
- if (LLMarketplaceInventoryImporter::instance().getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
- {
- // Hide merchant outbox related menu item
- gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(FALSE);
-
- // Launch a Merchant Outbox test connection to get the migration status
- LLMarketplaceInventoryImporter::instance().setStatusReportCallback(boost::bind(&set_merchant_outbox_menu,_1, _2));
- LLMarketplaceInventoryImporter::instance().initialize();
- }
}
}
@@ -2139,6 +2107,22 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t
+///////////////////////
+// CHECK FOR UPDATES //
+///////////////////////
+
+
+
+class LLAdvancedCheckViewerUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterAboutUtil::checkUpdatesAndNotify();
+ return true;
+ }
+};
+
+
////////////////////
// COMPRESS IMAGE //
////////////////////
@@ -7140,11 +7124,10 @@ void handle_selected_texture_info(void*)
{
msg.append( llformat("%d ", (S32)(it->second[i])));
}
-
- LLSD args;
- args["MESSAGE"] = msg;
- LLNotificationsUtil::add("SystemMessage", args);
}
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
}
}
@@ -8920,6 +8903,7 @@ void initialize_menus()
// Advanced (toplevel)
view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckViewerUpdates(), "Advanced.CheckViewerUpdates");
view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 782a27a846..4f24dfafac 100755
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -66,7 +66,6 @@
// linden libraries
#include "lleconomy.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llsdutil.h"
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 4e1a86bb71..d995ce4cdf 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -57,6 +57,7 @@
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
#include "llfirstuse.h"
+#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
#include "llfloaterland.h"
#include "llfloaterregioninfo.h"
@@ -120,6 +121,8 @@
#include "llnotificationmanager.h" //
#include "llexperiencecache.h"
+#include "llexperiencecache.h"
+
#if LL_MSVC
// disable boost::lexical_cast warning
#pragma warning (disable:4702)
@@ -2349,7 +2352,8 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s
LLNotificationsUtil::add("GodMessage", args);
// Treat like a system message and put in chat history.
- chat.mText = av_name.getCompleteName() + ": " + message;
+ chat.mSourceType = CHAT_SOURCE_SYSTEM;
+ chat.mText = message;
LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (nearby_chat)
@@ -2681,6 +2685,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["sender_name"] = name;
payload["group_id"] = group_id;
payload["inventory_name"] = item_name;
+ payload["received_time"] = LLDate::now();
if(info && info->asLLSD())
{
payload["inventory_offer"] = info->asLLSD();
@@ -2860,6 +2865,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
case IM_FROM_TASK:
{
+
if (is_do_not_disturb && !is_owned_by_me)
{
return;
@@ -2943,17 +2949,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["from_id"] = from_id;
payload["slurl"] = location;
payload["name"] = name;
- std::string session_name;
+
if (from_group)
{
payload["group_owned"] = "true";
}
- LLNotification::Params params("ServerObjectMessage");
- params.substitutions = substitutions;
- params.payload = payload;
-
- LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group);
+ LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);
}
break;
@@ -3490,53 +3492,29 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
LLNotificationsUtil::add("CallingCardDeclined");
}
-class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
+void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language)
{
-public :
- ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg,
- const LLChat &chat, const LLSD &toast_args)
- : LLTranslate::TranslationReceiver(from_lang, to_lang),
- m_chat(chat),
- m_toastArgs(toast_args),
- m_origMesg(mesg)
- {
- }
-
- static ChatTranslationReceiver* build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args)
- {
- return new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args);
- }
-
-protected:
- void handleResponse(const std::string &translation, const std::string &detected_language)
- {
- // filter out non-interesting responeses
- if ( !translation.empty()
- && (mToLang != detected_language)
- && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) )
- {
- m_chat.mText += " (" + translation + ")";
- }
+ // filter out non-interesting responses
+ if (!translation.empty()
+ && ((detected_language.empty()) || (expectLang != detected_language))
+ && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0))
+ {
+ chat.mText += " (" + translation + ")";
+ }
- LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
- }
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
+}
- void handleFailure(int status, const std::string& err_msg)
- {
- LL_WARNS() << "Translation failed for mesg " << m_origMesg << " toLang " << mToLang << " fromLang " << mFromLang << LL_ENDL;
+void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string err_msg)
+{
+ std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
+ LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
+ chat.mText += " (" + msg + ")";
- std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
- LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
- m_chat.mText += " (" + msg + ")";
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
+}
- LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
- }
-private:
- LLChat m_chat;
- std::string m_origMesg;
- LLSD m_toastArgs;
-};
void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
{
LLChat chat;
@@ -3772,8 +3750,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
const std::string from_lang = ""; // leave empty to trigger autodetect
const std::string to_lang = LLTranslate::getTranslateLanguage();
- LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, args);
- LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
+ LLTranslate::translateMessage(from_lang, to_lang, mesg,
+ boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2),
+ boost::bind(&translateFailure, chat, args, _1, _2));
+
}
else
{
@@ -3789,11 +3769,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
}
}
- LLSD msg_notify = LLSD(LLSD::emptyMap());
- msg_notify["session_id"] = LLUUID();
- msg_notify["from_id"] = chat.mFromID;
- msg_notify["source_type"] = chat.mSourceType;
- on_new_message(msg_notify);
+ if (mesg != "")
+ {
+ LLSD msg_notify = LLSD(LLSD::emptyMap());
+ msg_notify["session_id"] = LLUUID();
+ msg_notify["from_id"] = chat.mFromID;
+ msg_notify["source_type"] = chat.mSourceType;
+ on_new_message(msg_notify);
+ }
+
}
}
@@ -5635,6 +5619,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg)
}
}
final_args["MESSAGE"] = message;
+ payload["dest_id"] = dest_id;
notification = success ? "PaymentSent" : "PaymentFailure";
}
else {
@@ -6263,6 +6248,11 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use
gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));
}
}
+ LLFloaterBump* bumps_floater = LLFloaterBump::getInstance();
+ if(bumps_floater && bumps_floater->isInVisibleChain())
+ {
+ bumps_floater->populateCollisionList();
+ }
}
void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
@@ -6468,17 +6458,14 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
if (!region)
return false;
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return false;
- LLSD permission;
- LLSD data;
- permission["permission"]="Block";
+ LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), LLExperienceCache::ExperienceGetFn_t());
- data[experience.asString()]=permission;
- LLHTTPClient::put(lookup_url, data, NULL);
- data["experience"]=experience;
- LLEventPumps::instance().obtain("experience_permission").post(data);
+ LLSD permission;
+ LLSD data;
+ permission["permission"] = "Block";
+ data[experience.asString()] = permission;
+ data["experience"] = experience;
+ LLEventPumps::instance().obtain("experience_permission").post(data);
}
}
return false;
@@ -6653,7 +6640,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
else if(experienceid.notNull())
{
payload["experience"]=experienceid;
- LLExperienceCache::getInstance()->get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
+ LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
return;
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 190102ff0f..c1a7518ba2 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2885,6 +2885,9 @@ struct LLFilenameAndTask
{
LLUUID mTaskID;
std::string mFilename;
+
+ // for sequencing in case of multiple updates
+ S16 mSerial;
#ifdef _DEBUG
static S32 sCount;
LLFilenameAndTask()
@@ -2920,9 +2923,17 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
return;
}
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
+ // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update
+ msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial);
+
+ if (ft->mSerial < object->mInventorySerialNum)
+ {
+ // viewer did some changes to inventory that were not saved yet.
+ LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL;
+ object->mInventorySerialNum = ft->mSerial;
+ }
std::string unclean_filename;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
@@ -2962,9 +2973,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
{
LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
LLViewerObject* object = NULL;
- if(ft && (0 == error_code) &&
- (object = gObjectList.findObject(ft->mTaskID)))
+
+ if (ft
+ && (0 == error_code)
+ && (object = gObjectList.findObject(ft->mTaskID))
+ && ft->mSerial >= object->mInventorySerialNum)
{
+ object->mInventorySerialNum = ft->mSerial;
if (object->loadTaskInvFile(ft->mFilename))
{
@@ -2995,7 +3010,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
}
else
{
- // This Occurs When to requests were made, and the first one
+ // This Occurs When two requests were made, and the first one
// has already handled it.
LL_DEBUGS() << "Problem loading task inventory. Return code: "
<< error_code << LL_ENDL;
@@ -4637,7 +4652,7 @@ S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID
return retval;
}
-S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
S32 retval = 0;
const LLTextureEntry *tep = getTE(te);
@@ -4647,13 +4662,14 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
return 0;
}
- retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams);
+ setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
+ setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
+
+ retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams, isInitFromServer);
LL_DEBUGS("Material") << "Changing material params for te " << (S32)te
<< ", object " << mID
<< " (" << retval << ")"
<< LL_ENDL;
- setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
- setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
refreshMaterials();
return retval;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 05c87c153b..db2749f413 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -330,7 +330,7 @@ public:
/*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags );
/*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
/*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
// Used by Materials update functions to properly kick off rebuilds
// of VBs etc when materials updates require changes.
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 9b0035d547..5f01cdbb6f 100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -80,6 +80,9 @@
#include "llvocache.h"
#include "llcorehttputil.h"
+#include <algorithm>
+#include <iterator>
+
extern F32 gMinObjectDistance;
extern BOOL gAnimateTextures;
@@ -1021,38 +1024,35 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD idList;
- U32 objectIndex = 0;
- for (std::set<LLUUID>::iterator it = mStaleObjectCost.begin(); it != mStaleObjectCost.end(); )
- {
- // Check to see if a request for this object
- // has already been made.
- if (mPendingObjectCost.find(*it) == mPendingObjectCost.end())
- {
- mPendingObjectCost.insert(*it);
- idList[objectIndex++] = *it;
- }
- mStaleObjectCost.erase(it++);
+ uuid_set_t diff;
- if (objectIndex >= MAX_CONCURRENT_PHYSICS_REQUESTS)
- {
- break;
- }
- }
+ std::set_difference(mStaleObjectCost.begin(), mStaleObjectCost.end(),
+ mPendingObjectCost.begin(), mPendingObjectCost.end(),
+ std::inserter(diff, diff.begin()));
- if (idList.size() < 1)
+ if (diff.empty())
{
LL_INFOS() << "No outstanding object IDs to request." << LL_ENDL;
return;
}
-
+
+ LLSD idList(LLSD::emptyArray());
+
+ for (uuid_set_t::iterator it = diff.begin(); it != diff.end(); ++it)
+ {
+ idList.append(*it);
+ mStaleObjectCost.erase(*it);
+ }
+
+ mPendingObjectCost.insert(diff.begin(), diff.end());
+
LLSD postData = LLSD::emptyMap();
postData["object_ids"] = idList;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -1080,29 +1080,28 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url)
{
LLUUID objectId = it->asUUID();
+ // If the object was added to the StaleObjectCost set after it had been
+ // added to mPendingObjectCost it would still be in the StaleObjectCost
+ // set when we got the response back.
+ mStaleObjectCost.erase(objectId);
+ mPendingObjectCost.erase(objectId);
+
// Check to see if the request contains data for the object
if (result.has(it->asString()))
{
- const LLSD& data = result[it->asString()];
+ LLSD objectData = result[it->asString()];
- S32 shapeType = data["PhysicsShapeType"].asInteger();
-
- gObjectList.updatePhysicsShapeType(objectId, shapeType);
-
- if (data.has("Density"))
- {
- F32 density = data["Density"].asReal();
- F32 friction = data["Friction"].asReal();
- F32 restitution = data["Restitution"].asReal();
- F32 gravityMult = data["GravityMultiplier"].asReal();
+ F32 linkCost = objectData["linked_set_resource_cost"].asReal();
+ F32 objectCost = objectData["resource_cost"].asReal();
+ F32 physicsCost = objectData["physics_cost"].asReal();
+ F32 linkPhysicsCost = objectData["linked_set_physics_cost"].asReal();
- gObjectList.updatePhysicsProperties(objectId, density, friction, restitution, gravityMult);
- }
+ gObjectList.updateObjectCost(objectId, objectCost, linkCost, physicsCost, linkPhysicsCost);
}
else
{
// TODO*: Give user feedback about the missing data?
- gObjectList.onPhysicsFlagsFetchFailure(objectId);
+ gObjectList.onObjectCostFetchFailure(objectId);
}
}
@@ -1153,7 +1152,7 @@ void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url)
LLSD idList;
U32 objectIndex = 0;
- for (std::set<LLUUID>::iterator it = mStalePhysicsFlags.begin(); it != mStalePhysicsFlags.end(); )
+ for (uuid_set_t::iterator it = mStalePhysicsFlags.begin(); it != mStalePhysicsFlags.end();)
{
// Check to see if a request for this object
// has already been made.
@@ -1181,7 +1180,7 @@ void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url)
postData["object_ids"] = idList;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -1522,8 +1521,6 @@ void LLViewerObjectList::updateObjectCost(LLViewerObject* object)
void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost)
{
- mPendingObjectCost.erase(object_id);
-
LLViewerObject* object = findObject(object_id);
if (object)
{
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 9ec7c4bc22..94c751acc6 100755
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -205,17 +205,17 @@ protected:
vobj_list_t mMapObjects;
- std::set<LLUUID> mDeadObjects;
+ uuid_set_t mDeadObjects;
std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
//set of objects that need to update their cost
- std::set<LLUUID> mStaleObjectCost;
- std::set<LLUUID> mPendingObjectCost;
+ uuid_set_t mStaleObjectCost;
+ uuid_set_t mPendingObjectCost;
//set of objects that need to update their physics flags
- std::set<LLUUID> mStalePhysicsFlags;
- std::set<LLUUID> mPendingPhysicsFlags;
+ uuid_set_t mStalePhysicsFlags;
+ uuid_set_t mPendingPhysicsFlags;
std::vector<LLDebugBeacon> mDebugBeacons;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 57548b6e8f..b0280ef3e0 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -34,7 +34,6 @@
#include "llavatarnamecache.h" // name lookup cap url
#include "llfloaterreg.h"
#include "llmath.h"
-#include "llhttpclient.h"
#include "llregionflags.h"
#include "llregionhandle.h"
#include "llsurface.h"
@@ -274,7 +273,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
<< " (attempt #" << mSeedCapAttempts << ")" << LL_ENDL;
regionp = NULL;
- result = httpAdapter->postAndYield(httpRequest, url, capabilityNames);
+ result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
if (!regionp) //region was removed
@@ -311,6 +310,10 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
<< "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
}
+#if 0
+ log_capabilities(mCapabilities);
+#endif
+
regionp->setCapabilitiesReceived(true);
if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
@@ -364,7 +367,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL;
regionp = NULL;
- result = httpAdapter->postAndYield(httpRequest, url, capabilityNames);
+ result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
LLSD httpResults = result["http_result"];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -391,6 +394,10 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
//LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
}
+#if 0
+ log_capabilities(mCapabilities);
+#endif
+
if (mCapabilities.size() != mSecondCapabilitiesTracker.size())
{
LL_WARNS("AppInit", "Capabilities")
@@ -463,7 +470,7 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region
}
regionp = NULL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result["http_result"];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -2940,11 +2947,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
}
else if(name == "UntrustedSimulatorMessage")
{
-#if 1
mImpl->mHost.setUntrustedSimulatorCap(url);
-#else
- LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url));
-#endif
}
else if (name == "SimulatorFeatures")
{
@@ -3042,7 +3045,7 @@ void LLViewerRegion::setCapabilitiesReceived(bool received)
{
mCapabilitiesReceivedSignal(getRegionID());
- LLFloaterPermsDefault::sendInitialPerms();
+ //LLFloaterPermsDefault::sendInitialPerms();
// This is a single-shot signal. Forget callbacks to save resources.
mCapabilitiesReceivedSignal.disconnect_all_slots();
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 2c3067cd3a..f52c82dab7 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -60,6 +60,7 @@
#include "llfeaturemanager.h"
#include "llviewernetwork.h"
#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
+#include "llsdserialize.h"
#include "llcorehttputil.h"
namespace LLStatViewer
@@ -599,8 +600,10 @@ void send_stats()
body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
body["MinimalSkin"] = false;
-
+
LLViewerStats::getInstance()->addToMessage(body);
+
+ LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL;
LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
"Statistics posted to sim", "Failed to post statistics to sim");
LLViewerStats::instance().getRecording().resume();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index db949437a7..e0932ec36e 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -160,6 +160,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
+const F32 MAX_STANDOFF_FROM_ORIGIN = 3;
+const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
+
// Discard level at which to switch to baked textures
// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
const S32 SWITCH_TO_BAKED_DISCARD = 5;
@@ -2132,7 +2135,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
// animate the character
// store off last frame's root position to be consistent with camera position
- LLVector3 root_pos_last = mRoot->getWorldPosition();
+ mLastRootPos = mRoot->getWorldPosition();
BOOL detailed_update = updateCharacter(agent);
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
@@ -2150,7 +2153,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateWindEffect();
}
- idleUpdateNameTag( root_pos_last );
+ idleUpdateNameTag( mLastRootPos );
idleUpdateRenderCost();
}
@@ -6080,10 +6083,10 @@ void LLVOAvatar::getOffObject()
{
return;
}
-
+
LLViewerObject* sit_object = (LLViewerObject*)getParent();
- if (sit_object)
+ if (sit_object)
{
stopMotionFromSource(sit_object->getID());
LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
@@ -6100,9 +6103,19 @@ void LLVOAvatar::getOffObject()
}
// assumes that transform will not be updated with drawable still having a parent
+ // or that drawable had no parent from the start
LLVector3 cur_position_world = mDrawable->getWorldPosition();
LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
+ if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN
+ && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN
+ || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE))
+ {
+ // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent
+ // restore coordinates from cache
+ cur_position_world = mLastRootPos;
+ }
+
// set *local* position based on last *world* position, since we're unparenting the avatar
mDrawable->mXform.setPosition(cur_position_world);
mDrawable->mXform.setRotation(cur_rotation_world);
@@ -6278,6 +6291,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
+ && (!mOrphaned || isSelf())
&& (mDrawable->isVisible() || mIsDummy);
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 1c3f4f2aa7..5b4379165a 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -869,6 +869,8 @@ public:
private:
// set this property only with LLVOAvatar::sitDown method
BOOL mIsSitting;
+ // position backup in case of missing data
+ LLVector3 mLastRootPos;
/** Hierarchy
** **
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index fb2171ccc2..e7dee14387 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2203,7 +2203,7 @@ void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url)
gPendingMetricsUploads++;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, msg);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, msg);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index 192d50ae9b..3abb716593 100755
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -617,7 +617,7 @@ void LLVoiceChannelGroup::voiceCallCapCoro(std::string url)
LL_INFOS("Voice", "voiceCallCapCoro") << "Generic POST for " << url << LL_ENDL;
- LLSD result = httpAdapter->postAndYield(httpRequest, url, postData);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index f50ffdeae7..d14fac5fb8 100755
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -462,7 +462,7 @@ void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries)
httpOpts->setRetries(retries);
- LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD(), httpOpts);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -3941,7 +3941,7 @@ void LLVivoxVoiceClient::parcelVoiceInfoRequestCoro(std::string url)
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
state requestingState = getState();
- LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD());
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD());
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 0432f6f27c..19d61f6e33 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
+bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
+{
+ bool regen_faces = false;
+
+ LLVolume *old_volumep, *new_volumep;
+ F32 old_lod, new_lod;
+ S32 old_num_faces, new_num_faces;
+
+ old_volumep = getVolume();
+ old_lod = old_volumep->getDetail();
+ old_num_faces = old_volumep->getNumFaces();
+ old_volumep = NULL;
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
+ const LLVolumeParams &volume_params = getVolume()->getParams();
+ setVolume(volume_params, 0);
+ }
+
+ new_volumep = getVolume();
+ new_lod = new_volumep->getDetail();
+ new_num_faces = new_volumep->getNumFaces();
+ new_volumep = NULL;
+
+ if ((new_lod != old_lod) || mSculptChanged)
+ {
+ compiled = TRUE;
+ sNumLODChanges += new_num_faces;
+
+ if ((S32)getNumTEs() != getVolume()->getNumFaces())
+ {
+ setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
+ }
+
+ drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
+ regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
+ if (regen_faces)
+ {
+ regenFaces();
+ }
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
+ }
+ }
+
+ return regen_faces;
+}
+
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES);
@@ -1664,83 +1724,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
return TRUE; // No update to complete
}
- if (mVolumeChanged || mFaceMappingChanged )
+ if (mVolumeChanged || mFaceMappingChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
- compiled = TRUE;
+ bool was_regen_faces = false;
if (mVolumeChanged)
{
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
-
+ else if (mSculptChanged || mLODChanged)
{
+ compiled = TRUE;
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
+ }
+
+ if (!was_regen_faces) {
LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
regenFaces();
- genBBoxes(FALSE);
}
+
+ genBBoxes(FALSE);
}
- else if ((mLODChanged) || (mSculptChanged))
+ else if (mLODChanged || mSculptChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
-
- LLVolume *old_volumep, *new_volumep;
- F32 old_lod, new_lod;
- S32 old_num_faces, new_num_faces ;
-
- old_volumep = getVolume();
- old_lod = old_volumep->getDetail();
- old_num_faces = old_volumep->getNumFaces() ;
- old_volumep = NULL ;
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
- }
-
- new_volumep = getVolume();
- new_lod = new_volumep->getDetail();
- new_num_faces = new_volumep->getNumFaces() ;
- new_volumep = NULL ;
-
- if ((new_lod != old_lod) || mSculptChanged)
- {
- compiled = TRUE;
- sNumLODChanges += new_num_faces ;
-
- if((S32)getNumTEs() != getVolume()->getNumFaces())
- {
- setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
- }
-
- drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
- if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs())
- {
- regenFaces();
- }
- genBBoxes(FALSE);
-
- if (mSculptChanged)
- { //changes in sculpt maps can thrash an object bounding box without
- //triggering a spatial group bounding box update -- force spatial group
- //to update bounding boxes
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->unbound();
- }
- }
- }
- }
-
+ compiled = TRUE;
+ lodOrSculptChanged(drawable, compiled);
genBBoxes(FALSE);
}
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
@@ -2010,7 +2022,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM
LLTextureEntry* texture_entry = pVol->getTE(te);
if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))
{
- pVol->setTEMaterialParams(te, pMaterialParams);
+ pVol->setTEMaterialParams(te, pMaterialParams, FALSE);
}
}
}
@@ -2081,7 +2093,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2158,7 +2170,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2167,7 +2179,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
return 0 != new_material.size();
}
-S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams);
@@ -2264,7 +2276,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa
}
}
- S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial);
+ S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer);
LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
@@ -4163,7 +4175,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
//build matrix palette
- static const size_t kMaxJoints = 64;
+ static const size_t kMaxJoints = 52;
LLMatrix4a mp[kMaxJoints];
LLMatrix4* mat = (LLMatrix4*) mp;
@@ -4172,6 +4184,12 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
for (U32 j = 0; j < maxJoints; ++j)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (!joint)
+ {
+ // Fall back to a point inside the avatar if mesh is
+ // rigged to an unknown joint.
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[j] = skin->mInvBindMatrix[j];
@@ -4216,8 +4234,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
wght[k] = w - floorf(w);
scale += wght[k];
}
-
- wght *= 1.f/scale;
+ // This is enforced in unpackVolumeFaces()
+ llassert(scale>0.f);
+ wght *= 1.f / scale;
for (U32 k = 0; k < 4; k++)
{
@@ -4225,9 +4244,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LLMatrix4a src;
// Insure ref'd bone is in our clamped array of mats
- llassert(idx[k] < kMaxJoints);
- // clamp k to kMaxJoints to avoid reading garbage off stack in release
- src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w);
+ // clamp idx to maxJoints to avoid reading garbage off stack in release
+ S32 index = llclamp((S32)idx[k],(S32)0,(S32)kMaxJoints-1);
+ src.setMul(mp[index], w);
final_mat.add(src);
}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index bbaca316b0..ff7438ac09 100755
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -192,7 +192,7 @@ public:
static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
/*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
/*virtual*/ S32 setTEScaleS(const U8 te, const F32 s);
/*virtual*/ S32 setTEScaleT(const U8 te, const F32 t);
@@ -339,6 +339,10 @@ protected:
void cleanUpMediaImpls();
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
void removeMediaImpl(S32 texture_index) ;
+
+private:
+ bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
+
public:
static S32 getRenderComplexityMax() {return mRenderComplexity_last;}
diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp
index 2033a5f36a..06ce497510 100755
--- a/indra/newview/llwebprofile.cpp
+++ b/indra/newview/llwebprofile.cpp
@@ -124,7 +124,7 @@ void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::strin
httpHeaders = buildDefaultHeaders();
httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie());
- LLSD result = httpAdapter->getJsonAndYield(httpRequest, configUrl, httpOpts, httpHeaders);
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, configUrl, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -150,7 +150,7 @@ void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::strin
LLCore::BufferArray::ptr_t body = LLWebProfile::buildPostData(data, image, boundary);
- result = httpAdapter->postAndYield(httpRequest, uploadUrl, body, httpOpts, httpHeaders);
+ result = httpAdapter->postAndSuspend(httpRequest, uploadUrl, body, httpOpts, httpHeaders);
body.reset();
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
@@ -178,7 +178,7 @@ void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::strin
LL_DEBUGS("Snapshots") << "Got redirection URL: " << redirUrl << LL_ENDL;
- result = httpAdapter->getRawAndYield(httpRequest, redirUrl, httpOpts, httpHeaders);
+ result = httpAdapter->getRawAndSuspend(httpRequest, redirUrl, httpOpts, httpHeaders);
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
index ff15afa598..87e8c3008e 100755
--- a/indra/newview/llwlhandlers.cpp
+++ b/indra/newview/llwlhandlers.cpp
@@ -101,7 +101,7 @@ void LLEnvironmentRequest::environmentRequestCoro(std::string url)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
if (requestId != LLEnvironmentRequest::sLastRequest)
{
@@ -126,7 +126,7 @@ void LLEnvironmentRequest::environmentRequestCoro(std::string url)
regionId = gAgent.getRegion()->getRegionID();
}
- if (result[0]["regionID"].asUUID() != regionId)
+ if ((result[0]["regionID"].asUUID() != regionId) && regionId.notNull())
{
LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
<< regionId << " but got " << result[0]["regionID"].asUUID()
@@ -185,7 +185,7 @@ void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content)
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentApply", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLSD result = httpAdapter->postAndYield(httpRequest, url, content);
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, content);
LLSD notify; // for error reporting. If there is something to report to user this will be defined.
/*
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index bfae142812..837b30586b 100755
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -383,6 +383,7 @@ void LLWorldMap::reloadItems(bool force)
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT);
}
}
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 5828aee7fc..f8b38669b6 100755
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -34,8 +34,8 @@
#include "llxmlrpctransaction.h"
#include "llxmlrpclistener.h"
-#include "llcurl.h"
#include "httpcommon.h"
+#include "llhttpconstants.h"
#include "httprequest.h"
#include "httpoptions.h"
#include "httpheaders.h"
@@ -175,7 +175,7 @@ public:
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
- typedef boost::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t;
+ typedef boost::shared_ptr<LLXMLRPCTransaction::Handler> ptr_t;
private:
@@ -390,7 +390,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this ));
mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
- mURI, body.get(), httpOpts, httpHeaders, mHandler.get());
+ mURI, body.get(), httpOpts, httpHeaders, mHandler);
}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 03712c1065..57e2faca5b 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -105,7 +105,6 @@
#include "llspatialpartition.h"
#include "llmutelist.h"
#include "lltoolpie.h"
-#include "llcurl.h"
#include "llnotifications.h"
#include "llpathinglib.h"
#include "llfloaterpathfindingconsole.h"
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index bdc884885f..8533625e50 100755
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -873,8 +873,11 @@
<color
name="ToolbarDropZoneColor"
value=".48 .69 1 .5" />
-
- <!-- Generic color names (legacy) -->
+ <color
+ name="PanelNotificationListItem"
+ value="0.3 0.3 0.3 .3" />
+
+ <!-- Generic color names (legacy) -->
<color
name="white"
value="1 1 1 1"/>
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
new file mode 100644
index 0000000000..0732a33d93
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
new file mode 100644
index 0000000000..8124554902
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
new file mode 100644
index 0000000000..4d245eb57a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
new file mode 100644
index 0000000000..186822da43
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Large.png b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
new file mode 100644
index 0000000000..434ce3e8b6
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Small.png b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
new file mode 100644
index 0000000000..027a8446d8
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a5f2ce1f84..e453d94883 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -804,4 +804,9 @@ with the same filename but different name
<texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
<texture name="NavBar Separator" file_name="navbar/separator.png"/>
+ <texture name="Notification_Condense" file_name="icons/Icon_Notification_Condense.png" preload="true"/>
+ <texture name="Notification_Expand" file_name="icons/Icon_Notification_Expand.png" preload="true"/>
+ <texture name="System_Notification" file_name="icons/SL_Logo.png" preload="true"/>
+ <texture name="Icon_Attachment_Small" file_name="icons/Icon_Attachment_Small.png" preload="true"/>
+ <texture name="Icon_Attachment_Large" file_name="icons/Icon_Attachment_Large.png" preload="true"/>
</textures>
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index aa6bc53672..299322001b 100755
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -37,7 +37,7 @@
<menu_item_separator/>
<menu_item_call label="Profil for sted" name="Place Profile"/>
<menu_item_call label="Om land" name="About Land"/>
- <menu_item_call label="Region/Estate" name="Region/Estate"/>
+ <menu_item_call label="Region/Estate" name="RegionEstate"/>
<menu_item_call label="Køb dette land" name="Buy Land"/>
<menu_item_call label="Mit land" name="My Land"/>
<menu label="Vis" name="LandShow">
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 33b876bdb9..aad3b9d062 100755
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -1311,9 +1311,6 @@ Prøv igen om lidt.
<notification name="NoValidCircuit">
Ingen gyldig kode for kredsløb.
</notification>
- <notification name="NoValidTimestamp">
- Ikke et gyldigt klokkeslæt.
- </notification>
<notification name="NoPendingConnection">
Kunne ikke skabe fast forbindelse.
</notification>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 1924ff4ec3..956530c990 100755
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Fliegen" name="Fly"/>
<menu_item_check label="Immer rennen" name="Always Run"/>
<menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/>
- <menu_item_call label="Gehen/Rennen/Fliegen..." name="Walk / run / fly"/>
+ <menu_item_call label="Gehen/Rennen/Fliegen..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Abwesend" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Ortsprofil" name="Place Profile"/>
<menu_item_call label="Landinformationen" name="About Land"/>
- <menu_item_call label="Region/Grundbesitz" name="Region/Estate"/>
+ <menu_item_call label="Region/Grundbesitz" name="RegionEstate"/>
<menu_item_call label="Mein Landbesitz..." name="My Land"/>
<menu_item_call label="Dieses Land kaufen" name="Buy Land"/>
<menu label="Anzeigen" name="LandShow">
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 0b1c18cd51..fa7db0a8a3 100755
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2802,9 +2802,6 @@ Versuchen Sie es in einigen Minuten erneut.
<notification name="NoValidCircuit">
Kein gültiger Verbindungscode.
</notification>
- <notification name="NoValidTimestamp">
- Kein gültiger Zeitstempel.
- </notification>
<notification name="NoPendingConnection">
Verbindung kann nicht hergestellt werden.
</notification>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 60f36770bb..ec87b3684e 100755
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -43,6 +43,14 @@
top_pad="5"
height="25"
width="180" />
+ <button
+ follows="left|top"
+ label="Check for updates"
+ name="update_btn"
+ left_pad="70"
+ top_delta="0"
+ height="25"
+ width="180" />
</panel>
<panel
border="true"
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 90d45d5ebc..edf028bf60 100755
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -2013,7 +2013,7 @@ Only large parcels can be listed in search.
name="AllowedText"
top="0"
width="230">
- Allowed Residents
+ Allowed Residents ([COUNT])
</text>
<name_list
column_padding="0"
@@ -2062,7 +2062,7 @@ Only large parcels can be listed in search.
name="BanCheck"
top="0"
width="200">
- Banned Residents
+ Banned Residents ([COUNT])
</text>
<name_list
column_padding="0"
diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml
index 1f2fe62b3c..126e3aac48 100755
--- a/indra/newview/skins/default/xui/en/floater_bumps.xml
+++ b/indra/newview/skins/default/xui/en/floater_bumps.xml
@@ -7,7 +7,7 @@
help_topic="floater_bumps"
save_rect="true"
title="BUMPS, PUSHES &amp; HITS"
- width="400">
+ width="420">
<floater.string
name="none_detected">
None detected
@@ -34,7 +34,7 @@
</floater.string>
<floater.string
name="timeStr">
- [[hour,datetime,slt]:[min,datetime,slt]]
+ [[hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt]]
</floater.string>
<scroll_list
draw_border="false"
@@ -45,5 +45,5 @@
multi_select="true"
name="bump_list"
top="20"
- width="388" />
+ width="408" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_experiences.xml b/indra/newview/skins/default/xui/en/floater_experiences.xml
index 70e7507907..442da887c5 100644
--- a/indra/newview/skins/default/xui/en/floater_experiences.xml
+++ b/indra/newview/skins/default/xui/en/floater_experiences.xml
@@ -12,7 +12,7 @@
name="floater_experiences"
save_rect="true"
single_instance="true"
- reuse_instance="false"
+
bg_opaque_color="0 0.5 0 0.3"
title="EXPERIENCES">
<tab_container
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index a4acd1df78..7183b2f1f9 100755
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -31,6 +31,7 @@
<string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
<string name="mesh_status_missing_lod">Missing required level of detail.</string>
<string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
+ <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
<string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
<string name="decomposing">Analyzing...</string>
<string name="simplifying">Simplifying...</string>
@@ -66,7 +67,7 @@
follows="top|left"
layout="topleft"
height="19"
- max_length_bytes="64"
+ max_length_bytes="63"
name="description_form"
prevalidate_callback="ascii"
top_pad="5"
@@ -1027,19 +1028,19 @@
bg_alpha_color="0 0 0 0"
bg_opaque_color="0 0 0 0.3"
follows="left|top"
- height="16"
+ height="19"
layout="topleft"
left="18"
name="physics info"
- top_pad="15"
- width="589">
+ top_pad="12"
+ width="319">
<text
follows="top|left"
height="15"
layout="topleft"
left="0"
text_color="White"
- top_pad="0"
+ top_pad="3"
name="results_text"
width="50">
Results:
@@ -1077,6 +1078,33 @@
Hulls: [HULLS]
</text>
</panel>
+ <panel
+ bg_alpha_color="0 0 0 0"
+ bg_opaque_color="0 0 0 0.3"
+ follows="left|top"
+ height="19"
+ layout="topleft"
+ left_pad="5"
+ top_delta="0"
+ name="physics message"
+ width="270">
+ <icon
+ follows="left|top"
+ height="16"
+ left="0"
+ layout="topleft"
+ name="physics_status_message_icon"
+ top_pad="0"
+ width="16" />
+ <text
+ follows="left|top"
+ height="15"
+ layout="topleft"
+ left_pad="2"
+ name="physics_status_message_text"
+ width="252"
+ top_delta="3"/>
+ </panel>
</panel>
<!-- MODIFIERS PANEL -->
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
new file mode 100644
index 0000000000..afc609de52
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater
+ legacy_header_height="18"
+ bevel_style="in"
+ layout="topleft"
+ name="floater_notifications_tabbed"
+ help_topic="notification_chiclet"
+ save_rect="true"
+ title="NOTIFICATIONS"
+ width="350"
+ min_width="435"
+ height="550"
+ min_height="150"
+ can_minimize="false"
+ can_tear_off="false"
+ can_resize="true"
+ can_drag_on_left="false"
+ can_dock="true"
+ save_dock_state="true"
+ save_visibility="true"
+ single_instance="true"
+>
+ <floater.string
+ name="system_tab_title">
+ System ([COUNT])
+ </floater.string>
+ <floater.string
+ name="transactions_tab_title">
+ Transactions ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_invitations_tab_title">
+ Invitations ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_notices_tab_title">
+ Group ([COUNT])
+ </floater.string>
+
+ <string
+ name="title_notification_tabbed_window">
+ NOTIFICATIONS
+ </string>
+ <layout_stack
+ width="336"
+ height="533"
+ enabled="true"
+ orientation="vertical"
+ name="TabButtonsStack"
+ follows="left|top|right|bottom"
+ top="17">
+ <layout_panel
+ width="336"
+ height="530"
+ enabled="true"
+ name="TabButtonsLayoutPanel">
+ <tab_container
+ follows="left|top|right|bottom"
+ halign="center"
+ layout="topleft"
+ tab_position="top"
+ left="7"
+ top="7"
+ width="336"
+ height="491"
+ mouse_opaque="true"
+ name="notifications_tab_container">
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="System (0)"
+ layout="topleft"
+ name="system_notification_list_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="system_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="330"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Transactions (0)"
+ layout="topleft"
+ name="transaction_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="transaction_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Invitations (0)"
+ layout="topleft"
+ name="group_invite_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_invite_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Group (0)"
+ layout="topleft"
+ name="group_notice_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_notice_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ </tab_container>
+
+ <layout_stack width="336" height="26" enabled="true" orientation="horizontal" follows="left|right" name="ButtonsStack">
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="CondenseAllButtonPanel">
+ <button width="93" height="21" left="2" label="Collapse all" name="collapse_all_button">
+ </button>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="GapLayoutPanel">
+ <panel width="90" height="21" left="2" label="Gap Panel" border="false" name="GapPanel">
+ </panel>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="DeleteAllButtonPanel">
+ <button width="93" height="21" left="2" label="Delete all" name="delete_all_button">
+ </button>
+ </layout_panel>
+ </layout_stack>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml
index ecedb27438..2c5176cf01 100755
--- a/indra/newview/skins/default/xui/en/floater_sys_well.xml
+++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml
@@ -23,10 +23,6 @@
name="title_im_well_window">
CONVERSATIONS
</string>
- <string
- name="title_notification_well_window">
- NOTIFICATIONS
- </string>
<flat_list_view
color="FloaterDefaultBackgroundColor"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 91adec0789..61002bf1b5 100755
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -565,14 +565,6 @@
<menu_item_call
label="Delete"
layout="topleft"
- name="Remove Link">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="delete" />
- </menu_item_call>
- <menu_item_call
- label="Delete"
- layout="topleft"
name="Delete">
<menu_item_call.on_click
function="Inventory.DoToSelected"
@@ -785,14 +777,6 @@
layout="topleft"
name="Marketplace Separator" />
<menu_item_call
- label="Copy to Merchant Outbox"
- layout="topleft"
- name="Merchant Copy">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="copy_to_outbox" />
- </menu_item_call>
- <menu_item_call
label="Copy to Marketplace Listings"
layout="topleft"
name="Marketplace Copy">
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index e91eea04d1..73ca7c529d 100755
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -108,6 +108,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu_item_check
label="Show Debug Menu"
diff --git a/indra/newview/skins/default/xui/en/menu_url_email.xml b/indra/newview/skins/default/xui/en/menu_url_email.xml
new file mode 100644
index 0000000000..6467fe5c90
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_url_email.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Email Popup">
+ <menu_item_call
+ label="Compose Email in an External client"
+ layout="topleft"
+ name="email_open_external">
+ <menu_item_call.on_click
+ function="Url.OpenExternal" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Copy Email to clipboard"
+ layout="topleft"
+ name="email_copy">
+ <menu_item_call.on_click
+ function="Url.CopyLabel" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2463c5f43b..f22986438c 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -134,7 +134,7 @@
</menu_item_call>
<menu_item_call
label="Walk / run / fly..."
- name="Walk / run / fly">
+ name="WalkRunFly">
<menu_item_call.on_click
function="Floater.ToggleOrBringToFront"
parameter="moveview" />
@@ -173,13 +173,6 @@
<menu_item_call.on_click
function="BuyCurrency" />
</menu_item_call>
- <menu_item_call
- label="Merchant Outbox..."
- name="MerchantOutbox">
- <menu_item_call.on_click
- function="Floater.ToggleOrBringToFront"
- parameter="outbox" />
- </menu_item_call>
<menu_item_call
label="Marketplace listings..."
name="MarketplaceListings">
@@ -509,7 +502,7 @@
</menu_item_call>
<menu_item_call
label="Region / Estate"
- name="Region/Estate">
+ name="RegionEstate">
<menu_item_call.on_click
function="Floater.Show"
parameter="region_info" />
@@ -1438,7 +1431,7 @@
function="Floater.Show"
parameter="bumps" />
</menu_item_call>
- <menu_item_separator/>
+ <menu_item_separator/>
<menu_item_call
label="About [APP_NAME]"
name="About Second Life">
@@ -1446,6 +1439,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu
create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f847c73287..f79e8103b6 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -244,7 +244,7 @@ You don't have permission to copy one or more of these items to the Merchant Out
<notification
icon="OutboxStatus_Success"
name="OutboxFolderCreated"
- type="outbox">
+ type="alertmodal">
<unique/>
A new folder has been created for each item you have transferred into the top level of your Merchant Outbox.
@@ -257,7 +257,7 @@ A new folder has been created for each item you have transferred into the top le
<notification
icon="OutboxStatus_Success"
name="OutboxImportComplete"
- type="outbox">
+ type="alertmodal">
Success
All folders were successfully sent to the Marketplace.
@@ -271,7 +271,7 @@ All folders were successfully sent to the Marketplace.
<notification
icon="OutboxStatus_Warning"
name="OutboxImportHadErrors"
- type="outbox">
+ type="alertmodal">
Some folders did not transfer
Errors occurred when some folders were sent to the Marketplace. Those folders are still in your Merchant Outbox.
@@ -286,7 +286,7 @@ See the [[MARKETPLACE_IMPORTS_URL] error log] for more information.
<notification
icon="OutboxStatus_Error"
name="OutboxImportFailed"
- type="outbox">
+ type="alertmodal">
Transfer failed with error &apos;[ERROR_CODE]&apos;
No folders were sent to the Marketplace because of a system or network error. Try again later.
@@ -299,7 +299,7 @@ No folders were sent to the Marketplace because of a system or network error. T
<notification
icon="OutboxStatus_Error"
name="OutboxInitFailed"
- type="outbox">
+ type="alertmodal">
Marketplace initialization failed with error &apos;[ERROR_CODE]&apos;
Initialization with the Marketplace failed because of a system or network error. Try again later.
@@ -312,7 +312,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="StockPasteFailed"
- type="outbox">
+ type="alertmodal">
Copy or move to Stock Folder failed with error :
&apos;[ERROR_CODE]&apos;
@@ -325,7 +325,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="MerchantPasteFailed"
- type="outbox">
+ type="alertmodal">
Copy or move to Marketplace Listings failed with error :
&apos;[ERROR_CODE]&apos;
@@ -338,7 +338,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="MerchantTransactionFailed"
- type="outbox">
+ type="alertmodal">
The transaction with the Marketplace failed with the following error :
Reason : &apos;[ERROR_REASON]&apos;
@@ -352,7 +352,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="MerchantUnprocessableEntity"
- type="outbox">
+ type="alertmodal">
We are unable to list this product or activate the version folder. Usually this is caused by missing information in the listing description form, but it may be due to errors in the folder structure. Either edit the listing or check the listing folder for errors.
<usetemplate
@@ -363,7 +363,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="MerchantListingFailed"
- type="outbox">
+ type="alertmodal">
Listing to Marketplace failed with error :
&apos;[ERROR_CODE]&apos;
@@ -376,7 +376,7 @@ Initialization with the Marketplace failed because of a system or network error.
<notification
icon="OutboxStatus_Error"
name="MerchantFolderActivationFailed"
- type="outbox">
+ type="alertmodal">
Activating this version folder failed with error :
&apos;[ERROR_CODE]&apos;
@@ -819,6 +819,33 @@ If you no longer wish to have these abilities granted to this role, disable them
notext="Cancel"
yestext="Eject"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMemberWarning"
+ type="alertmodal">
+ You are about to ban [AVATAR_NAME] from the group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning a participant from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMembersWarning"
+ type="alertmodal">
+ You are about to ban [COUNT] members from group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning multiple members from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -3892,6 +3919,53 @@ see [[INFO_URL] Information about this update]
name="okbutton"
yestext="OK"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadInProgress"
+ type="alertmodal">
+An update is available!
+It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadComplete"
+ type="alertmodal">
+An update was downloaded. It will be installed during restart.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateCheckError"
+ type="alertmodal">
+An error occured while checking for update.
+Please try again later.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateViewerUpToDate"
+ type="alertmodal">
+Your viewer is up to date!
+If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -4217,6 +4291,21 @@ You have reached your maximum number of groups. Please leave some group before j
<notification
icon="alert.tga"
+ name="GroupLimitInfo"
+ type="alert">
+The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium]
+accounts is [MAX_PREMIUM].
+If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more.
+
+[https://secondlife.com/my/account/membership.php Upgrade today!]
+ <tag>group</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="Close"/>
+ </notification>
+
+ <notification
+ icon="alert.tga"
name="KickUser"
type="alert">
<tag>win</tag>
@@ -7029,15 +7118,6 @@ No valid circuit code.
<notification
icon="notify.tga"
- name="NoValidTimestamp"
- persist="true"
- type="notify">
- <tag>fail</tag>
-No valid timestamp.
- </notification>
-
- <notification
- icon="notify.tga"
name="NoPendingConnection"
persist="true"
type="notify">
diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
index c76b958eda..c357f9e7d5 100644
--- a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
+++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
@@ -47,19 +47,19 @@
height="12"
follows="top|left">
</text>
- <scroll_list
+ <name_list
draw_heading="false"
left="3"
width="225"
height="75"
follows="all"
name="experience_list">
- <columns
+ <name_list.columns
width="225"
user_resize="false"
name="experience_name"
label="Name"/>
- </scroll_list>
+ </name_list>
<button
layout="topleft"
follows="top|right"
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 0518688f45..0a85477bf4 100755
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -21,7 +21,7 @@
</panel.string>
<panel.string
name="ItemcountUnknown">
-
+ Fetched [ITEM_COUNT] Items [FILTER]
</panel.string>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_notification_list_item.xml b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
new file mode 100644
index 0000000000..a909028f9f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- All our XML is utf-8 encoded. -->
+<panel
+ translate="false"
+ name="main_panel"
+ title="panel_notification_list_item"
+ visible="true"
+ top="0"
+ left="0"
+ width="331"
+ height="202"
+ can_resize="true"
+ layout="topleft"
+ follows="left|top|right|bottom" >
+ <!-- background_opaque="false" -->
+ <!-- background_visible="true"> -->
+ <!-- bg_alpha_color="PanelNotificationListItem"> -->
+ <panel.string
+ name="sender_resident_text">
+ Sender: "[SENDER_RESIDENT]"
+ </panel.string>
+ <panel.string
+ name="group_name_text">
+ Group: "[GROUP_NAME]"
+ </panel.string>
+ <panel.string
+ name="group_fee_text">
+ Fee: [GROUP_FEE]
+ </panel.string>
+ <panel.string
+ name="item_condensed_height">
+ 50
+ </panel.string>
+ <panel.string
+ name="item_expanded_height">
+ 87
+ </panel.string>
+ <panel.string
+ name="expanded_height_resize_for_attachment">
+ 27
+ </panel.string>
+
+ <panel top="0" left="0" width="331" height="196" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_total_view">
+ <layout_stack top="0" left="0" width="331" height="196" orientation="vertical" follows="left|top|right|bottom" name="item_vertical_stack">
+ <layout_panel top="0" left="0" height="30" follows="left|top|right|bottom" layout="topleft" name="layout_panel_condensed_view" visible="false" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="30" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_condensed_view">
+ <layout_stack top="0" left="0" width="325" height="50" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="39" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_right">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ </layout_panel>
+ <layout_panel width="260" height="50" orientation="horizontal" name="layout_panel_middle">
+ <panel border="false" top="0" width="260" height="38" bevel_style="none" follows="left|top|right" layout="topleft" name="main_info_panel">
+ <panel border="false" top="0" left="0" width="260" height="19" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="notification_title_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="6" left="0" width="260" height="12" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="true" mouse_opaque="false" name="notification_title" >
+ Group Name:Notice Title N o t i c e T i t l e N o t i c e T i t l e N o t i c e T i t l e N oticeTitle
+ </text>
+ <icon top="1" left="242" width="21" height="21" image_name="Icon_Attachment_Small" follows="right" mouse_opaque="true" name="attachment_icon" tool_tip="Attachment" visible="false"/>
+ </panel>
+ <panel border="false" top="23" left="0" width="260" height="15" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="sender_time_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="170" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-5" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time" value="2014/12/24 23:30" />
+ </panel>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" height="48" orientation="horizontal" follows="right|top|bottom" name="layout_panel_right">
+ <panel top="0" left="0" width="17" height="39" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel">
+ <button top="0" left="0" width="17" height="17" layout="topleft" follows="top" name="close_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="-16" right="15" width="17" height="17" layout="topleft" follows="bottom" name="expand_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Expand" image_selected="Notification_Expand" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ <layout_panel top="0" left="0" height="196" follows="left|top|right|bottom" layout="topleft" name="layout_panel_expanded_view" visible="true" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="panel_expanded_view">
+ <layout_stack top="0" left="0" width="325" height="196" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="170" orientation="horizontal" follows="left|top|bottom" name="layout_panel_right_exp">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon_exp" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon_exp" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon_exp" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ <icon left="12" top="144" width="20" height="20" name="attachment_icon_exp" tool_tip="Attachment" image_name="Icon_Attachment_Large" follows="left" mouse_opaque="true" visible="false"/>
+ </layout_panel>
+ <layout_panel width="230" height="196" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_middle_exp">
+ <panel border="false" top="0" width="230" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="main_info_panel_expanded">
+ <panel border="false" top="0" left="0" width="230" height="30" bevel_style="none" follows="left|top|right" layout="topleft" name="notification_title_panel_exp" >
+ <text allow_scroll="false" font="SansSerif" top="6" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="notification_title_exp">
+ Notice Title Notice Title N o t i c e T i t l e N o t i c e T i t l e
+ </text>
+ <text allow_scroll="false" font="SansSerif" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="group_name_exp" parse_urls="false" visible="false">
+ Group Name Group Name Group Na m e e
+ </text>
+ </panel>
+ <panel border="false" left="0" width="230" height="15" bevel_style="none" follows="left|top|right" layout="topleft" name="sender_time_panel_exp">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="145" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box_exp" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-1" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time_exp" value="2014/12/24 23:30" />
+ </panel>
+ <panel border="false" left="0" height="115" width="230" bevel_style="none" follows="all" layout="topleft" name="notification_text_panel_exp" visible="true">
+ <chat_editor is_expandable="true" top="0" left="0" width="230" height="110" layout="topleft" follows="left|right"
+ word_wrap="true" max_length="65536" name="notification_text_exp" parse_urls="true">
+ Notice text goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </chat_editor>
+ </panel>
+ <panel border="false" left="1" bottom="-5" width="230" height="22" bevel_style="none" follows="left|right|bottom" layout="topleft" name="attachment_panel" visible="false">
+ <text allow_scroll="false" font="SansSerifSmall" top="4" left="5" width="220" height="12" layout="topleft" follows="left|top|right|bottom"
+ use_ellipses="true" word_wrap="true" max_length="96" name="attachment_text">
+ Attachment goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </text>
+ </panel>
+ <panel border="false" left="1" bottom="-5" height="55" bevel_style="none" follows="left|right|bottom" layout="topleft" name="button_panel" visible="false">
+ <button top="2" left="0" width="65" height="23" layout="topleft" follows="left|top|bottom" name="join_btn" mouse_opaque="true" tab_stop="false" label = "Join"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="decline_btn" mouse_opaque="true" tab_stop="false" label = "Decline"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="info_btn" mouse_opaque="true" tab_stop="false" label = "Info"/>
+ </panel>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" orientation="horizontal" follows="right|top|bottom" name="layout_panel_left_exp">
+ <panel top="0" left="0" width="17" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel_exp">
+ <button top="0" left="2" width="17" height="17" layout="topleft" follows="top" name="close_expanded_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="5" left="0" width="17" height="17" layout="topleft" follows="bottom" name="condense_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Condense" image_selected="Notification_Condense" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 2d4665c128..4fb8b9a67f 100755
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left="3"
use_ellipses="true"
name="groupcount">
- You belong to [COUNT] groups, and can join [REMAINING] more.
+ You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Want more?]
</text>
<group_list
allow_select="true"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index 2e778014c5..3e96160834 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -216,7 +216,7 @@
control_name="QAMode"
follows="top|left"
height="15"
- label="Show Developer Menu"
+ label="Show Develop Menu"
layout="topleft"
left="30"
name="show_develop_menu_check"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 1e9a1aa27c..b201e071ef 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -270,7 +270,7 @@
value="1" />
-->
<combo_box.item
- label="Download and install updates manually"
+ label="I will download and install updates manually"
name="Install_manual"
value="0" />
</combo_box>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index b7e0cff146..4eb6e2462d 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -238,6 +238,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
<string name="TooltipTooManyWearables">You can't wear a folder containing more than [AMOUNT] items. You can change this limit in Advanced > Show Debug Settings > WearFolderLimit.</string>
<string name="TooltipPrice" value="L$[AMOUNT]: "/>
+ <string name="TooltipSLIcon">This links to a page on the official SecondLife.com or LindenLab.com domain.</string>
<string name="TooltipOutboxDragToWorld">You can't rez items from the Marketplace Listings folder</string>
<string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string>
@@ -277,6 +278,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMapUrl">Click to view this location on a map</string>
<string name="TooltipSLAPP">Click to run the secondlife:// command</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" />
+ <string name="TooltipEmail">Click to compose an email</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleport to</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
new file mode 100644
index 0000000000..150225af27
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<notification_list_view
+ allow_select="false"
+ color="PanelFocusBackgroundColor"
+ item_pad="0"
+ keep_one_selected="false"
+ multi_select="false"
+ opaque="true">
+ <flat_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="notification_list"
+ left="1"
+ top="20"
+ height="0"
+ width="318"/>
+</notification_list_view> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 5118171d80..f6ebb498ec 100755
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Volar" name="Fly"/>
<menu_item_check label="Correr siempre" name="Always Run"/>
<menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/>
- <menu_item_call label="Caminar / Correr / Volar..." name="Walk / run / fly"/>
+ <menu_item_call label="Caminar / Correr / Volar..." name="WalkRunFly"/>
</menu>
<menu label="Estado" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -63,7 +63,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil del lugar" name="Place Profile"/>
<menu_item_call label="Acerca del terreno" name="About Land"/>
- <menu_item_call label="Región/Estado" name="Region/Estate"/>
+ <menu_item_call label="Región/Estado" name="RegionEstate"/>
<menu_item_call label="Mis terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 9578e1b863..1e367b33fc 100755
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2796,9 +2796,6 @@ Por favor, vuelve a intentarlo en unos momentos.
<notification name="NoValidCircuit">
Circuito de código inválido.
</notification>
- <notification name="NoValidTimestamp">
- Fecha inválida.
- </notification>
<notification name="NoPendingConnection">
No se puede crear la conexión.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index 33b2ba6982..788cdbf856 100755
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voler" name="Fly"/>
<menu_item_check label="Toujours courir" name="Always Run"/>
<menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/>
- <menu_item_call label="Marcher / Courir / Voler..." name="Walk / run / fly"/>
+ <menu_item_call label="Marcher / Courir / Voler..." name="WalkRunFly"/>
</menu>
<menu label="Statut" name="Status">
<menu_item_check label="Absent" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Photo" name="Take Snapshot"/>
<menu_item_call label="Profil du lieu" name="Place Profile"/>
<menu_item_call label="À propos du terrain" name="About Land"/>
- <menu_item_call label="Région/Domaine" name="Region/Estate"/>
+ <menu_item_call label="Région/Domaine" name="RegionEstate"/>
<menu_item_call label="Mes terrains..." name="My Land"/>
<menu_item_call label="Acheter ce terrain" name="Buy Land"/>
<menu label="Afficher" name="LandShow">
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index f13a80fe61..29e6fe1979 100755
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2788,9 +2788,6 @@ Veuillez réessayer dans quelques minutes.
<notification name="NoValidCircuit">
Aucun code de circuit valide.
</notification>
- <notification name="NoValidTimestamp">
- Timestamp non valide.
- </notification>
<notification name="NoPendingConnection">
Impossible de créer la connexion en attente.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index 40082cb265..2b8249c8a9 100755
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<panel name="panel_login">
<panel.string name="forgot_password_url">http://secondlife.com/account/request.php?lang=fr</panel.string>
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=fr
- </panel.string>
<layout_stack name="ui_stack">
<layout_panel name="ui_container">
<combo_box label="Nom d&apos;utilisateur" name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index 3f4c370ccd..18ddad5ee8 100755
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Vola" name="Fly"/>
<menu_item_check label="Corri sempre" name="Always Run"/>
<menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/>
- <menu_item_call label="Cammina / corri / vola..." name="Walk / run / fly"/>
+ <menu_item_call label="Cammina / corri / vola..." name="WalkRunFly"/>
</menu>
<menu label="Stato" name="Status">
<menu_item_check label="Assente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Istantanea" name="Take Snapshot"/>
<menu_item_call label="Profilo del luogo" name="Place Profile"/>
<menu_item_call label="Informazioni sul terreno" name="About Land"/>
- <menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/>
+ <menu_item_call label="Regione/proprietà immobiliare" name="RegionEstate"/>
<menu_item_call label="Terreni posseduti..." name="My Land"/>
<menu_item_call label="Acquista questo terreno" name="Buy Land"/>
<menu label="Mostra" name="LandShow">
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 06f2b70dcf..61131b09c3 100755
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2793,9 +2793,6 @@ Riprova tra qualche istante.
<notification name="NoValidCircuit">
Nessun codice circuito valido.
</notification>
- <notification name="NoValidTimestamp">
- Nessuna data/timestamp valido.
- </notification>
<notification name="NoPendingConnection">
Impossibile creare la connessione in sospeso.
</notification>
diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml
index 3f756c5f94..0384dc1efc 100755
--- a/indra/newview/skins/default/xui/ja/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛ã¶" name="Fly"/>
<menu_item_check label="常ã«èµ°ã‚‹" name="Always Run"/>
<menu_item_call label="ç§ã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’åœæ­¢ã™ã‚‹" name="Stop Animating My Avatar"/>
- <menu_item_call label="æ­©è¡Œï¼èµ°è¡Œï¼é£›è¡Œ..." name="Walk / run / fly"/>
+ <menu_item_call label="æ­©è¡Œï¼èµ°è¡Œï¼é£›è¡Œ..." name="WalkRunFly"/>
</menu>
<menu label="ログイン" name="Status">
<menu_item_check label="一時退席中" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="スナップショット" name="Take Snapshot"/>
<menu_item_call label="場所ã®ãƒ—ロフィール" name="Place Profile"/>
<menu_item_call label="土地情報" name="About Land"/>
- <menu_item_call label="地域 / ä¸å‹•ç”£" name="Region/Estate"/>
+ <menu_item_call label="地域 / ä¸å‹•ç”£" name="RegionEstate"/>
<menu_item_call label="ä¿æœ‰åœ°..." name="My Land"/>
<menu_item_call label="ã“ã®åœŸåœ°ã‚’購入" name="Buy Land"/>
<menu label="表示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index 694f38467e..5f0ce7a73b 100755
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2836,9 +2836,6 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
<notification name="NoValidCircuit">
回路コードãŒç„¡åŠ¹ã§ã™ã€‚
</notification>
- <notification name="NoValidTimestamp">
- タイムスタンプãŒç„¡åŠ¹ã§ã™ã€‚
- </notification>
<notification name="NoPendingConnection">
接続を生æˆã§ãã¾ã›ã‚“。
</notification>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index ef3fe71945..6fd498eea8 100755
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -33,7 +33,7 @@
<menu_item_call label="Zrób zdjęcie" name="Take Snapshot"/>
<menu_item_call label="Profil miejsca" name="Place Profile"/>
<menu_item_call label="O posiadłości" name="About Land"/>
- <menu_item_call label="Region/MajÄ…tek" name="Region/Estate"/>
+ <menu_item_call label="Region/MajÄ…tek" name="RegionEstate"/>
<menu_item_call label="Moje posiadłości" name="My Land"/>
<menu_item_call label="Kup posiadłość" name="Buy Land"/>
<menu label="Pokaż" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 62fda0d601..c4a65d92b4 100755
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -2368,9 +2368,6 @@ Spróbuj ponowanie za kilka minut.
<notification name="NoValidCircuit">
Nieważny obwód kodowania.
</notification>
- <notification name="NoValidTimestamp">
- Niewłaściwy czas zapisu.
- </notification>
<notification name="NoPendingConnection">
Brak możliwości wykonania połączenia.
</notification>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 9b3b6077ed..3d5d9eccc6 100755
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voar" name="Fly"/>
<menu_item_check label="Correr sempre" name="Always Run"/>
<menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/>
- <menu_item_call label="Andar/correr/voar..." name="Walk / run / fly"/>
+ <menu_item_call label="Andar/correr/voar..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil da região" name="Place Profile"/>
<menu_item_call label="Sobre terrenos" name="About Land"/>
- <menu_item_call label="Região/Propriedade" name="Region/Estate"/>
+ <menu_item_call label="Região/Propriedade" name="RegionEstate"/>
<menu_item_call label="Meus terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 29b85d9e97..a264495404 100755
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -2777,9 +2777,6 @@ Por favor, tente novamente em alguns instantes.
<notification name="NoValidCircuit">
Código de circuito inválido.
</notification>
- <notification name="NoValidTimestamp">
- Hora inválida.
- </notification>
<notification name="NoPendingConnection">
Impossível criar a conexão pendente.
</notification>
diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml
index 958105a70f..d22ca845f9 100755
--- a/indra/newview/skins/default/xui/ru/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Полет" name="Fly"/>
<menu_item_check label="Ð’Ñегда бегать" name="Always Run"/>
<menu_item_call label="ОÑтановить анимацию" name="Stop Animating My Avatar"/>
- <menu_item_call label="Ходьба / бег / полет..." name="Walk / run / fly"/>
+ <menu_item_call label="Ходьба / бег / полет..." name="WalkRunFly"/>
</menu>
<menu label="СтатуÑ" name="Status">
<menu_item_check label="Ðет на меÑте" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Снимок" name="Take Snapshot"/>
<menu_item_call label="Профиль меÑта" name="Place Profile"/>
<menu_item_call label="О земле" name="About Land"/>
- <menu_item_call label="Регион/землевладение" name="Region/Estate"/>
+ <menu_item_call label="Регион/землевладение" name="RegionEstate"/>
<menu_item_call label="Мои владениÑ..." name="My Land"/>
<menu_item_call label="Купить Ñту землю" name="Buy Land"/>
<menu label="Показать" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index acf3ce608f..70b9a25590 100755
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -2788,9 +2788,6 @@ http://secondlife.com/download.
<notification name="NoValidCircuit">
Ðет подходÑщего кода канала.
</notification>
- <notification name="NoValidTimestamp">
- Ðет подходÑщей метки времени.
- </notification>
<notification name="NoPendingConnection">
Ðевозможно Ñоздать отложенное Ñоединение.
</notification>
diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml
index cc8d8c895b..cea57011dd 100755
--- a/indra/newview/skins/default/xui/tr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Uç" name="Fly"/>
<menu_item_check label="Daima KoÅŸ" name="Always Run"/>
<menu_item_call label="Beni Anime Etmeyi Durdur" name="Stop Animating My Avatar"/>
- <menu_item_call label="Yürü / koş / uç..." name="Walk / run / fly"/>
+ <menu_item_call label="Yürü / koş / uç..." name="WalkRunFly"/>
</menu>
<menu label="Durum" name="Status">
<menu_item_check label="Uzakta" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Anlık Görüntü" name="Take Snapshot"/>
<menu_item_call label="Profili yerleÅŸtir" name="Place Profile"/>
<menu_item_call label="Arazi hakkında" name="About Land"/>
- <menu_item_call label="Bölge / Gayrimenkul" name="Region/Estate"/>
+ <menu_item_call label="Bölge / Gayrimenkul" name="RegionEstate"/>
<menu_item_call label="Sahip olduğum arazi parçaları..." name="My Land"/>
<menu_item_call label="Bu araziyi satın al" name="Buy Land"/>
<menu label="Göster" name="LandShow">
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index a6c69c7ab2..df22251b3d 100755
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -2788,9 +2788,6 @@ Lütfen biraz sonra tekrar deneyin.
<notification name="NoValidCircuit">
Geçerli bir devre kodu yok.
</notification>
- <notification name="NoValidTimestamp">
- Geçerli bir zaman damgası yok.
- </notification>
<notification name="NoPendingConnection">
Beklemedeki bağlantı oluşturulamıyor.
</notification>
diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml
index e94f52a401..9572ad49d3 100755
--- a/indra/newview/skins/default/xui/zh/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛行" name="Fly"/>
<menu_item_check label="以跑代步" name="Always Run"/>
<menu_item_call label="åœæ­¢æˆ‘身上的動作" name="Stop Animating My Avatar"/>
- <menu_item_call label="行走 / 跑步 / 飛行…" name="Walk / run / fly"/>
+ <menu_item_call label="行走 / 跑步 / 飛行…" name="WalkRunFly"/>
</menu>
<menu label="狀態" name="Status">
<menu_item_check label="離開" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="å¿«ç…§" name="Take Snapshot"/>
<menu_item_call label="地點å°æª”案" name="Place Profile"/>
<menu_item_call label="土地資料" name="About Land"/>
- <menu_item_call label="地å€/領地" name="Region/Estate"/>
+ <menu_item_call label="地å€/領地" name="RegionEstate"/>
<menu_item_call label="我所æ“有的土地…" name="My Land"/>
<menu_item_call label="購買這塊土地" name="Buy Land"/>
<menu label="顯示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index 179f01e90d..0a98101b60 100755
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -2778,9 +2778,6 @@ SHA1 指紋:[MD5_DIGEST]
<notification name="NoValidCircuit">
沒有有效的線路碼。
</notification>
- <notification name="NoValidTimestamp">
- 沒有有效的時間戳記。
- </notification>
<notification name="NoPendingConnection">
無法建立待通的連線。
</notification>
diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp
index 8bd6cc2690..21c83184dc 100755
--- a/indra/newview/tests/llhttpretrypolicy_test.cpp
+++ b/indra/newview/tests/llhttpretrypolicy_test.cpp
@@ -234,13 +234,13 @@ void RetryPolicyTestObject::test<6>()
std::string str1("0");
seconds_to_wait = F32_MAX;
- success = getSecondsUntilRetryAfter(str1, seconds_to_wait);
+ success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str1, seconds_to_wait);
ensure("parse 1", success);
ensure_equals("parse 1", seconds_to_wait, 0.0);
std::string str2("999.9");
seconds_to_wait = F32_MAX;
- success = getSecondsUntilRetryAfter(str2, seconds_to_wait);
+ success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait);
ensure("parse 2", success);
ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8);
@@ -248,7 +248,7 @@ void RetryPolicyTestObject::test<6>()
time(&nowseconds);
std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123();
seconds_to_wait = F32_MAX;
- success = getSecondsUntilRetryAfter(str3, seconds_to_wait);
+ success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str3, seconds_to_wait);
std::cerr << " str3 [" << str3 << "]" << std::endl;
ensure("parse 3", success);
ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F);
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
deleted file mode 100755
index 5e73dbb981..0000000000
--- a/indra/newview/tests/lltranslate_test.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/**
- * @file lltranslate_test.cpp
- *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "../test/lltut.h"
-#include "../lltranslate.h"
-#include "../llversioninfo.h"
-#include "../llviewercontrol.h"
-
-#include "llbufferstream.h"
-#include "lltrans.h"
-#include "llui.h"
-
-#include "../../llmessage/llhttpconstants.cpp"
-
-static const std::string GOOGLE_VALID_RESPONSE1 =
-"{\
- \"data\": {\
- \"translations\": [\
- {\
- \"translatedText\": \"привет\",\
- \"detectedSourceLanguage\": \"es\"\
- }\
- ]\
- }\
-}";
-
-static const std::string GOOGLE_VALID_RESPONSE2 =
-"{\
- \"data\": {\
- \"translations\": [\
- {\
- \"translatedText\": \"привет\"\
- }\
- ]\
- }\
-}\
-";
-
-static const std::string GOOGLE_VALID_RESPONSE3 =
-"{\
- \"error\": {\
- \"errors\": [\
- {\
- \"domain\": \"global\",\
- \"reason\": \"invalid\",\
- \"message\": \"Invalid Value\"\
- }\
- ],\
- \"code\": 400,\
- \"message\": \"Invalid Value\"\
- }\
-}";
-
-static const std::string BING_VALID_RESPONSE1 =
-"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет</string>";
-
-static const std::string BING_VALID_RESPONSE2 =
-"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p><p>Parameter: </p>\
-<p>Message: 'from' must be a valid language</p><code></code>\
-<p>message id=3743.V2_Rest.Translate.58E8454F</p></body></html>";
-
-static const std::string BING_VALID_RESPONSE3 =
-"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p>\
-<p>Parameter: appId</p><p>Message: Invalid appId&#xD;\nParameter name: appId</p>\
-<code></code><p>message id=3737.V2_Rest.Translate.56016759</p></body></html>";
-
-namespace tut
-{
- class translate_test
- {
- protected:
- void test_translation(
- LLTranslationAPIHandler& handler,
- int status, const std::string& resp,
- const std::string& exp_trans, const std::string& exp_lang, const std::string& exp_err)
- {
- std::string translation, detected_lang, err_msg;
- bool rc = handler.parseResponse(status, resp, translation, detected_lang, err_msg);
- ensure_equals("rc", rc, (status == 200));
- ensure_equals("err_msg", err_msg, exp_err);
- ensure_equals("translation", translation, exp_trans);
- ensure_equals("detected_lang", detected_lang, exp_lang);
- }
-
- LLGoogleTranslationHandler mGoogle;
- LLBingTranslationHandler mBing;
- };
-
- typedef test_group<translate_test> translate_test_group_t;
- typedef translate_test_group_t::object translate_test_object_t;
- tut::translate_test_group_t tut_translate("LLTranslate");
-
- template<> template<>
- void translate_test_object_t::test<1>()
- {
- test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE1, "привет", "es", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<2>()
- {
- test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE2, "привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<3>()
- {
- test_translation(mGoogle, 400, GOOGLE_VALID_RESPONSE3, "", "", "Invalid Value");
- }
-
- template<> template<>
- void translate_test_object_t::test<4>()
- {
- test_translation(mGoogle, 400,
- "",
- "", "", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n");
- }
-
- template<> template<>
- void translate_test_object_t::test<5>()
- {
- test_translation(mGoogle, 400,
- "[]",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<6>()
- {
- test_translation(mGoogle, 400,
- "{\"oops\": \"invalid\"}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<7>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": {}}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<8>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": { \"translations\": [ {} ] }}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<9>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": { \"translations\": [ { \"translatedTextZZZ\": \"привет\", \"detectedSourceLanguageZZZ\": \"es\" } ] }}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<10>()
- {
- test_translation(mBing, 200, BING_VALID_RESPONSE1, "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<11>()
- {
- test_translation(mBing, 400, BING_VALID_RESPONSE2, "", "", "'from' must be a valid language");
- }
-
- template<> template<>
- void translate_test_object_t::test<12>()
- {
- test_translation(mBing, 400, BING_VALID_RESPONSE3, "", "", "Invalid appId\nParameter name: appId");
- }
-
- template<> template<>
- void translate_test_object_t::test<13>()
- {
- test_translation(mBing, 200,
- "Привет</string>",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<14>()
- {
- test_translation(mBing, 200,
- "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<15>()
- {
- test_translation(mBing, 200,
- "Привет",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<16>()
- {
- test_translation(mBing, 400,
- "Message: some error</p>",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<17>()
- {
- test_translation(mBing, 400,
- "Message: some error",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<18>()
- {
- test_translation(mBing, 400,
- "some error</p>",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<19>()
- {
- test_translation(mBing, 400,
- "some error",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<20>()
- {
- std::string url;
- mBing.getTranslateURL(url, "en", "es", "hi");
- ensure_equals("bing URL", url,
- "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es&from=en");
- }
-
- template<> template<>
- void translate_test_object_t::test<21>()
- {
- std::string url;
- mBing.getTranslateURL(url, "", "es", "hi");
- ensure_equals("bing URL", url,
- "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es");
- }
-
- template<> template<>
- void translate_test_object_t::test<22>()
- {
- std::string url;
- mGoogle.getTranslateURL(url, "en", "es", "hi");
- ensure_equals("google URL", url,
- "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es&source=en");
- }
-
- template<> template<>
- void translate_test_object_t::test<23>()
- {
- std::string url;
- mGoogle.getTranslateURL(url, "", "es", "hi");
- ensure_equals("google URL", url,
- "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es");
- }
-}
-
-//== Misc stubs ===============================================================
-LLControlGroup gSavedSettings("test");
-
-std::string LLUI::getLanguage() { return "en"; }
-std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { return "dummy"; }
-
-LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) {}
-std::string LLControlGroup::getString(const std::string& name) { return "dummy"; }
-LLControlGroup::~LLControlGroup() {}
-
-LLCurl::Responder::Responder() {}
-void LLCurl::Responder::httpFailure() { }
-void LLCurl::Responder::httpSuccess() { }
-void LLCurl::Responder::httpCompleted() { }
-void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
-LLCurl::Responder::~Responder() {}
-
-void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32, bool) {}
-void LLHTTPClient::get(const std::string&, LLPointer<LLCurl::Responder>, const LLSD&, const F32, bool) {}
-
-LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer)
-: std::iostream(&mStreamBuf), mStreamBuf(channels, buffer) {}
-LLBufferStream::~LLBufferStream() {}
-
-LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors&, LLBufferArray*) {}
-#if( LL_WINDOWS || __GNUC__ > 2)
-LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
- off_type off,
- std::ios::seekdir way,
- std::ios::openmode which)
-#else
-streampos LLBufferStreamBuf::seekoff(
- streamoff off,
- std::ios::seekdir way,
- std::ios::openmode which)
-#endif
-{ return 0; }
-int LLBufferStreamBuf::sync() {return 0;}
-int LLBufferStreamBuf::underflow() {return 0;}
-int LLBufferStreamBuf::overflow(int) {return 0;}
-LLBufferStreamBuf::~LLBufferStreamBuf() {}
-
-S32 LLVersionInfo::getBuild() { return 0; }
-const std::string& LLVersionInfo::getChannel() {static std::string dummy; return dummy;}
-S32 LLVersionInfo::getMajor() { return 0; }
-S32 LLVersionInfo::getMinor() { return 0; }
-S32 LLVersionInfo::getPatch() { return 0; }
diff --git a/indra/test/io.cpp b/indra/test/io.cpp
index 97726c2b92..ff900ab96b 100755
--- a/indra/test/io.cpp
+++ b/indra/test/io.cpp
@@ -41,8 +41,6 @@
#include "llpipeutil.h"
#include "llpumpio.h"
#include "llsd.h"
-#include "llsdrpcclient.h"
-#include "llsdrpcserver.h"
#include "llsdserialize.h"
#include "llcommon.h"
#include "lluuid.h"
@@ -1177,425 +1175,6 @@ namespace tut
}
}
-namespace tut
-{
- struct rpc_server_data
- {
- class LLSimpleRPCResponse : public LLSDRPCResponse
- {
- public:
- LLSimpleRPCResponse(LLSD* response) :
- mResponsePtr(response)
- {
- }
- ~LLSimpleRPCResponse()
- {
- }
- virtual bool response(LLPumpIO* pump)
- {
- *mResponsePtr = mReturnValue;
- return true;
- }
- virtual bool fault(LLPumpIO* pump)
- {
- *mResponsePtr = mReturnValue;
- return false;
- }
- virtual bool error(LLPumpIO* pump)
- {
- ensure("LLSimpleRPCResponse::error()", false);
- return false;
- }
- public:
- LLSD* mResponsePtr;
- };
-
- class LLSimpleRPCClient : public LLSDRPCClient
- {
- public:
- LLSimpleRPCClient(LLSD* response) :
- mResponsePtr(response)
- {
- }
- ~LLSimpleRPCClient() {}
- void echo(const LLSD& parameter)
- {
- LLSimpleRPCResponse* resp;
- resp = new LLSimpleRPCResponse(mResponsePtr);
- static const std::string URI_NONE;
- static const std::string METHOD_ECHO("echo");
- call(URI_NONE, METHOD_ECHO, parameter, resp, EPBQ_CALLBACK);
- }
- public:
- LLSD* mResponsePtr;
- };
-
- class LLSimpleRPCServer : public LLSDRPCServer
- {
- public:
- LLSimpleRPCServer()
- {
- mMethods["echo"] = new mem_fn_t(
- this,
- &LLSimpleRPCServer::rpc_Echo);
- }
- ~LLSimpleRPCServer() {}
- protected:
- typedef LLSDRPCMethodCall<LLSimpleRPCServer> mem_fn_t;
- ESDRPCSStatus rpc_Echo(
- const LLSD& parameter,
- const LLChannelDescriptors& channels,
- LLBufferArray* data)
- {
- buildResponse(channels, data, parameter);
- return ESDRPCS_DONE;
- }
- };
-
- apr_pool_t* mPool;
- LLPumpIO* mPump;
- LLPumpIO::chain_t mChain;
- LLSimpleRPCClient* mClient;
- LLSD mResponse;
-
- rpc_server_data() :
- mPool(NULL),
- mPump(NULL),
- mClient(NULL)
- {
- apr_pool_create(&mPool, NULL);
- mPump = new LLPumpIO(mPool);
- mClient = new LLSimpleRPCClient(&mResponse);
- mChain.push_back(LLIOPipe::ptr_t(mClient));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
- mChain.push_back(LLIOPipe::ptr_t(new LLSimpleRPCServer));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
- mChain.push_back(LLIOPipe::ptr_t(mClient));
- }
- ~rpc_server_data()
- {
- mChain.clear();
- delete mPump;
- mPump = NULL;
- apr_pool_destroy(mPool);
- mPool = NULL;
- }
- void pump_loop(const LLSD& request)
- {
- LLTimer timer;
- timer.setTimerExpirySec(1.0f);
- mClient->echo(request);
- mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS);
- while(mResponse.isUndefined() && !timer.hasExpired())
- {
- mPump->pump();
- mPump->callback();
- }
- }
- };
- typedef test_group<rpc_server_data> rpc_server_test;
- typedef rpc_server_test::object rpc_server_object;
- tut::rpc_server_test rpc("rpc_server");
-
- template<> template<>
- void rpc_server_object::test<1>()
- {
- LLSD request;
- request = 1;
- pump_loop(request);
- //LL_INFOS() << "request: " << *request << LL_ENDL;
- //LL_INFOS() << "response: " << *mResponse << LL_ENDL;
- ensure_equals("integer request response", mResponse.asInteger(), 1);
- }
-
- template<> template<>
- void rpc_server_object::test<2>()
- {
-//#if LL_WINDOWS && _MSC_VER >= 1400
-// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser.");
-//#endif
- std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
- std::stringstream stream;
- stream << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
- std::vector<U8> expected_binary;
- expected_binary.resize(stream.str().size());
- memcpy(&expected_binary[0], stream.str().c_str(), stream.str().size()); /* Flawfinder: ignore */
- stream.str("");
- stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
- << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
- << "'attachment_data':["
- << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},"
- << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << expected_binary.size() << ")\"";
- stream.write((const char*)&expected_binary[0], expected_binary.size());
- stream << "\"}"
- << "]"
- << "}]";
-
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- stream,
- stream.str().size());
- ensure("parsed something", (count > 0));
-
- pump_loop(request);
- ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
- ensure_equals("return size", mResponse.size(), 3);
-
- ensure_equals(
- "uri parameter type",
- mResponse[0].type(),
- LLSD::TypeMap);
- ensure_equals(
- "uri type",
- mResponse[0]["uri"].type(),
- LLSD::TypeString);
- ensure_equals("uri value", mResponse[0]["uri"].asString(), uri);
-
- ensure_equals(
- "version parameter type",
- mResponse[1].type(),
- LLSD::TypeMap);
- ensure_equals(
- "version type",
- mResponse[1]["version"].type(),
- LLSD::TypeInteger);
- ensure_equals(
- "version value",
- mResponse[1]["version"].asInteger(),
- 1);
-
- ensure_equals("agent params type", mResponse[2].type(), LLSD::TypeMap);
- LLSD attachment_data = mResponse[2]["attachment_data"];
- ensure("attachment data exists", attachment_data.isDefined());
- ensure_equals(
- "attachment type",
- attachment_data.type(),
- LLSD::TypeArray);
- ensure_equals(
- "attachment type 0",
- attachment_data[0].type(),
- LLSD::TypeMap);
- ensure_equals(
- "attachment type 1",
- attachment_data[1].type(),
- LLSD::TypeMap);
- ensure_equals("attachment size 1", attachment_data[1].size(), 3);
- ensure_equals(
- "asset data type",
- attachment_data[1]["asset_data"].type(),
- LLSD::TypeBinary);
- std::vector<U8> actual_binary;
- actual_binary = attachment_data[1]["asset_data"].asBinary();
- ensure_equals(
- "binary data size",
- actual_binary.size(),
- expected_binary.size());
- ensure(
- "binary data",
- (0 == memcmp(
- &actual_binary[0],
- &expected_binary[0],
- expected_binary.size())));
- }
-
- template<> template<>
- void rpc_server_object::test<3>()
- {
-//#if LL_WINDOWS && _MSC_VER >= 1400
-// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser.");
-//#endif
- std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
-
- LLBufferArray buffer;
- LLChannelDescriptors buffer_channels = buffer.nextChannel();
- LLBufferStream stream(buffer_channels, &buffer);
- stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
- << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
- << "'attachment_data':["
- << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},";
-
- std::stringstream tmp_str;
- tmp_str << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
- std::vector<U8> expected_binary;
- expected_binary.resize(tmp_str.str().size());
- memcpy( /* Flawfinder: ignore */
- &expected_binary[0],
- tmp_str.str().c_str(),
- tmp_str.str().size());
-
- LLBufferArray attachment_buffer;
- LLChannelDescriptors attach_channels = attachment_buffer.nextChannel();
- LLBufferStream attach_stream(attach_channels, &attachment_buffer);
- attach_stream.write((const char*)&expected_binary[0], expected_binary.size());
- attach_stream.flush();
- S32 len = attachment_buffer.countAfter(attach_channels.out(), NULL);
- stream << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << len << ")\"";
- stream.flush();
- buffer.takeContents(attachment_buffer);
- stream << "\"}]}]";
- stream.flush();
-
- LLChannelDescriptors read_channel = buffer.nextChannel();
- LLBufferStream read_stream(read_channel, &buffer);
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- read_stream,
- buffer.count(read_channel.in()));
- ensure("parsed something", (count > 0));
- ensure("deserialized", request.isDefined());
-
- // do the rpc round trip
- pump_loop(request);
-
- ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
- ensure_equals("return size", mResponse.size(), 3);
-
- LLSD child = mResponse[0];
- ensure("uri map exists", child.isDefined());
- ensure_equals("uri parameter type", child.type(), LLSD::TypeMap);
- ensure("uri string exists", child.has("uri"));
- ensure_equals("uri type", child["uri"].type(), LLSD::TypeString);
- ensure_equals("uri value", child["uri"].asString(), uri);
-
- child = mResponse[1];
- ensure("version map exists", child.isDefined());
- ensure_equals("version param type", child.type(), LLSD::TypeMap);
- ensure_equals(
- "version type",
- child["version"].type(),
- LLSD::TypeInteger);
- ensure_equals("version value", child["version"].asInteger(), 1);
-
- child = mResponse[2];
- ensure("agent params map exists", child.isDefined());
- ensure_equals("agent params type", child.type(), LLSD::TypeMap);
- child = child["attachment_data"];
- ensure("attachment data exists", child.isDefined());
- ensure_equals("attachment type", child.type(), LLSD::TypeArray);
- LLSD attachment = child[0];
- ensure_equals("attachment type 0", attachment.type(), LLSD::TypeMap);
- attachment = child[1];
- ensure_equals("attachment type 1", attachment.type(), LLSD::TypeMap);
- ensure_equals("attachment size 1", attachment.size(), 3);
- ensure_equals(
- "asset data type",
- attachment["asset_data"].type(),
- LLSD::TypeBinary);
- std::vector<U8> actual_binary = attachment["asset_data"].asBinary();
- ensure_equals(
- "binary data size",
- actual_binary.size(),
- expected_binary.size());
- ensure(
- "binary data",
- (0 == memcmp(
- &actual_binary[0],
- &expected_binary[0],
- expected_binary.size())));
- }
-
- template<> template<>
- void rpc_server_object::test<4>()
- {
- std::string message("parcel '' is naughty.");
- std::stringstream str;
- str << "{'message':'" << LLSDNotationFormatter::escapeString(message)
- << "'}";
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- str,
- str.str().size());
- ensure_equals("parse count", count, 2);
- ensure_equals("request type", request.type(), LLSD::TypeMap);
- pump_loop(request);
- ensure("valid response", mResponse.isDefined());
- ensure_equals("response type", mResponse.type(), LLSD::TypeMap);
- std::string actual = mResponse["message"].asString();
- ensure_equals("message contents", actual, message);
- }
-
- template<> template<>
- void rpc_server_object::test<5>()
- {
- // test some of the problem cases with llsdrpc over xmlrpc -
- // for example:
- // * arrays are auto-converted to parameter lists, thus, this
- // becomes one parameter.
- // * undef goes over the wire as false (this might not be a good idea)
- // * uuids are converted to string.
- std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]";
- std::istringstream istr;
- istr.str(val);
- LLSD sd;
- LLSDSerialize::fromNotation(sd, istr, val.size());
- pump_loop(sd);
- ensure("valid response", mResponse.isDefined());
- ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap);
- ensure_equals("parsed size", mResponse.size(), 2);
- LLSD failures = mResponse["failures"];
- ensure_equals("no failures.", failures.asBoolean(), false);
- LLSD success = mResponse["successfuls"];
- ensure_equals("success type", success.type(), LLSD::TypeArray);
- ensure_equals("success size", success.size(), 1);
- ensure_equals(
- "success instance type",
- success[0].type(),
- LLSD::TypeString);
- }
-
-/*
- template<> template<>
- void rpc_server_object::test<5>()
- {
- std::string expected("\xf3");//\xffsomething");
- LLSD* request = LLSD::createString(expected);
- pump_loop(request);
- std::string actual;
- mResponse->getString(actual);
- if(actual != expected)
- {
- //LL_WARNS() << "iteration " << i << LL_ENDL;
- std::ostringstream e_str;
- std::string::iterator iter = expected.begin();
- std::string::iterator end = expected.end();
- for(; iter != end; ++iter)
- {
- e_str << (S32)((U8)(*iter)) << " ";
- }
- e_str << std::endl;
- llsd_serialize_string(e_str, expected);
- LL_WARNS() << "expected size: " << expected.size() << LL_ENDL;
- LL_WARNS() << "expected: " << e_str.str() << LL_ENDL;
-
- std::ostringstream a_str;
- iter = actual.begin();
- end = actual.end();
- for(; iter != end; ++iter)
- {
- a_str << (S32)((U8)(*iter)) << " ";
- }
- a_str << std::endl;
- llsd_serialize_string(a_str, actual);
- LL_WARNS() << "actual size: " << actual.size() << LL_ENDL;
- LL_WARNS() << "actual: " << a_str.str() << LL_ENDL;
- }
- ensure_equals("binary string request response", actual, expected);
- delete request;
- }
-
- template<> template<>
- void rpc_server_object::test<5>()
- {
- }
-*/
-}
-
-
/*
'asset_data':b(12100)"{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemID STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"
*/
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index aa23699de0..8718360f0c 100755
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -28,7 +28,7 @@
#include <tut/tut.hpp>
#include "linden_common.h"
#include "lltut.h"
-
+#include "llhttpconstants.h"
#include "llapr.h"
#include "llmessageconfig.h"
#include "llsdserialize.h"
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 88415ff11a..53d4acc9e0 100755
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -108,7 +108,7 @@ private:
// In a coroutine's top-level function args, do NOT NOT NOT accept
// references (const or otherwise) to anything! Pass by value only!
- void login_(std::string uri, LLSD credentials);
+ void loginCoro(std::string uri, LLSD credentials);
LLEventStream mPump;
LLSD mAuthResponse, mValidAuthResponse;
@@ -122,11 +122,11 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
// its first wait; at that point, return here.
std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_",
- boost::bind(&Impl::login_, this, uri, login_params));
+ boost::bind(&Impl::loginCoro, this, uri, login_params));
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
-void LLLogin::Impl::login_(std::string uri, LLSD login_params)
+void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
try
{
@@ -143,43 +143,6 @@ void LLLogin::Impl::login_(std::string uri, LLSD login_params)
LLEventStream replyPump("SRVreply", true);
// Should be an array of one or more uri strings.
- LLSD rewrittenURIs;
- {
- LLEventTimeout filter(replyPump);
- sendProgressEvent("offline", "srvrequest");
-
- // Request SRV record.
- LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
-
- // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
- F32 seconds_to_timeout = 5.0f;
- if(login_params.has("cfg_srv_timeout"))
- {
- seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
- }
-
- // If the SRV request times out (e.g. EXT-3934), simulate response: an
- // array containing our original URI.
- LLSD fakeResponse(LLSD::emptyArray());
- fakeResponse.append(uri);
- filter.eventAfter(seconds_to_timeout, fakeResponse);
-
- std::string srv_pump_name = "LLAres";
- if(login_params.has("cfg_srv_pump"))
- {
- srv_pump_name = login_params["cfg_srv_pump"].asString();
- }
-
- // Make request
- LLSD request;
- request["op"] = "rewriteURI";
- request["uri"] = uri;
- request["reply"] = replyPump.getName();
- rewrittenURIs = llcoro::postAndWait(request, srv_pump_name, filter);
- // EXP-772: If rewrittenURIs fail, try original URI as a fallback.
- rewrittenURIs.append(uri);
- } // we no longer need the filter
-
LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
// EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used
// to share them -- but the EXT-3934 fix made it possible for an abandoned
@@ -190,107 +153,103 @@ void LLLogin::Impl::login_(std::string uri, LLSD login_params)
// Because of possible redirect responses, we may make more than one
// attempt per rewrittenURIs entry.
LLSD::Integer attempts = 0;
- for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()),
- urend(rewrittenURIs.endArray());
- urit != urend; ++urit)
+
+ LLSD request(login_params);
+ request["reply"] = loginReplyPump.getName();
+ request["uri"] = uri;
+ std::string status;
+
+ // Loop back to here if login attempt redirects to a different
+ // request["uri"]
+ for (;;)
{
- LLSD request(login_params);
- request["reply"] = loginReplyPump.getName();
- request["uri"] = *urit;
- std::string status;
-
- // Loop back to here if login attempt redirects to a different
- // request["uri"]
- for (;;)
+ ++attempts;
+ LLSD progress_data;
+ progress_data["attempt"] = attempts;
+ progress_data["request"] = request;
+ if(progress_data["request"].has("params")
+ && progress_data["request"]["params"].has("passwd"))
+ {
+ progress_data["request"]["params"]["passwd"] = "*******";
+ }
+ sendProgressEvent("offline", "authenticating", progress_data);
+
+ // We expect zero or more "Downloading" status events, followed by
+ // exactly one event with some other status. Use postAndSuspend() the
+ // first time, because -- at least in unit-test land -- it's
+ // possible for the reply to arrive before the post() call
+ // returns. Subsequent responses, of course, must be awaited
+ // without posting again.
+ for (mAuthResponse = validateResponse(loginReplyPump.getName(),
+ llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply"));
+ mAuthResponse["status"].asString() == "Downloading";
+ mAuthResponse = validateResponse(loginReplyPump.getName(),
+ llcoro::suspendUntilEventOn(loginReplyPump)))
{
- ++attempts;
- LLSD progress_data;
- progress_data["attempt"] = attempts;
- progress_data["request"] = request;
- if(progress_data["request"].has("params")
- && progress_data["request"]["params"].has("passwd"))
- {
- progress_data["request"]["params"]["passwd"] = "*******";
- }
- sendProgressEvent("offline", "authenticating", progress_data);
-
- // We expect zero or more "Downloading" status events, followed by
- // exactly one event with some other status. Use postAndWait() the
- // first time, because -- at least in unit-test land -- it's
- // possible for the reply to arrive before the post() call
- // returns. Subsequent responses, of course, must be awaited
- // without posting again.
- for (mAuthResponse = validateResponse(loginReplyPump.getName(),
- llcoro::postAndWait(request, xmlrpcPump, loginReplyPump, "reply"));
- mAuthResponse["status"].asString() == "Downloading";
- mAuthResponse = validateResponse(loginReplyPump.getName(),
- llcoro::waitForEventOn(loginReplyPump)))
- {
- // Still Downloading -- send progress update.
- sendProgressEvent("offline", "downloading");
- }
+ // Still Downloading -- send progress update.
+ sendProgressEvent("offline", "downloading");
+ }
- LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
- status = mAuthResponse["status"].asString();
-
- // Okay, we've received our final status event for this
- // request. Unless we got a redirect response, break the retry
- // loop for the current rewrittenURIs entry.
- if (!(status == "Complete" &&
- mAuthResponse["responses"]["login"].asString() == "indeterminate"))
- {
- break;
- }
-
- sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
-
- // Here the login service at the current URI is redirecting us
- // to some other URI ("indeterminate" -- why not "redirect"?).
- // The response should contain another uri to try, with its
- // own auth method.
- request["uri"] = mAuthResponse["responses"]["next_url"].asString();
- request["method"] = mAuthResponse["responses"]["next_method"].asString();
- } // loop back to try the redirected URI
-
- // Here we're done with redirects for the current rewrittenURIs
- // entry.
- if (status == "Complete")
+ LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
+ status = mAuthResponse["status"].asString();
+
+ // Okay, we've received our final status event for this
+ // request. Unless we got a redirect response, break the retry
+ // loop for the current rewrittenURIs entry.
+ if (!(status == "Complete" &&
+ mAuthResponse["responses"]["login"].asString() == "indeterminate"))
{
- // StatusComplete does not imply auth success. Check the
- // actual outcome of the request. We've already handled the
- // "indeterminate" case in the loop above.
- if (mAuthResponse["responses"]["login"].asString() == "true")
- {
- sendProgressEvent("online", "connect", mAuthResponse["responses"]);
- }
- else
- {
- sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
- }
- return; // Done!
+ break;
}
- /* Sometimes we end with "Started" here. Slightly slow server?
- * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
- */
- if( status == "Started")
- {
- LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
- continue;
- }
+ sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
- // If we don't recognize status at all, trouble
- if (! (status == "CURLError"
- || status == "XMLRPCError"
- || status == "OtherError"))
+ // Here the login service at the current URI is redirecting us
+ // to some other URI ("indeterminate" -- why not "redirect"?).
+ // The response should contain another uri to try, with its
+ // own auth method.
+ request["uri"] = mAuthResponse["responses"]["next_url"].asString();
+ request["method"] = mAuthResponse["responses"]["next_method"].asString();
+ } // loop back to try the redirected URI
+
+ // Here we're done with redirects for the current rewrittenURIs
+ // entry.
+ if (status == "Complete")
+ {
+ // StatusComplete does not imply auth success. Check the
+ // actual outcome of the request. We've already handled the
+ // "indeterminate" case in the loop above.
+ if (mAuthResponse["responses"]["login"].asString() == "true")
+ {
+ sendProgressEvent("online", "connect", mAuthResponse["responses"]);
+ }
+ else
{
- LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
- << mAuthResponse << LL_ENDL;
- return;
+ sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
}
+ return; // Done!
+ }
- // Here status IS one of the errors tested above.
- } // Retry if there are any more rewrittenURIs.
+// /* Sometimes we end with "Started" here. Slightly slow server?
+// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
+// */
+// if( status == "Started")
+// {
+// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
+// continue;
+// }
+
+ // If we don't recognize status at all, trouble
+ if (! (status == "CURLError"
+ || status == "XMLRPCError"
+ || status == "OtherError"))
+ {
+ LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
+ << mAuthResponse << LL_ENDL;
+ return;
+ }
+
+ // Here status IS one of the errors tested above.
// Here we got through all the rewrittenURIs without succeeding. Tell
// caller this didn't work out so well. Of course, the only failure data
@@ -351,29 +310,8 @@ LLEventPump& LLLogin::getEventPump()
// The list associates to event with the original idle_startup() 'STATE'.
-// Rewrite URIs
- // State_LOGIN_AUTH_INIT
-// Given a vector of login uris (usually just one), perform a dns lookup for the
-// SRV record from each URI. I think this is used to distribute login requests to
-// a single URI to multiple hosts.
-// This is currently a synchronous action. (See LLSRV::rewriteURI() implementation)
-// On dns lookup error the output uris == the input uris.
-//
-// Input: A vector of login uris
-// Output: A vector of login uris
-//
-// Code:
-// std::vector<std::string> uris;
-// LLViewerLogin::getInstance()->getLoginURIs(uris);
-// std::vector<std::string>::const_iterator iter, end;
-// for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
-// {
-// std::vector<std::string> rewritten;
-// rewritten = LLSRV::rewriteURI(*iter);
-// sAuthUris.insert(sAuthUris.end(),
-// rewritten.begin(), rewritten.end());
-// }
-// sAuthUriNum = 0;
+// Setup login
+// State_LOGIN_AUTH_INIT
// Authenticate
// STATE_LOGIN_AUTHENTICATE
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
index 58bf371a04..e96c495446 100755
--- a/indra/viewer_components/login/tests/lllogin_test.cpp
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -96,61 +96,6 @@ public:
}
};
-class LLAresListener: public LLEventTrackable
-{
- std::string mName;
- LLSD mEvent;
- bool mImmediateResponse;
- bool mMultipleURIResponse;
- Debug mDebug;
-
-public:
- LLAresListener(const std::string& name,
- bool i = false,
- bool m = false
- ) :
- mName(name),
- mImmediateResponse(i),
- mMultipleURIResponse(m),
- mDebug(stringize(*this))
- {}
-
- bool handle_event(const LLSD& event)
- {
- mDebug(STRINGIZE("LLAresListener called!: " << event));
- mEvent = event;
- if(mImmediateResponse)
- {
- sendReply();
- }
- return false;
- }
-
- void sendReply()
- {
- if(mEvent["op"].asString() == "rewriteURI")
- {
- LLSD result;
- if(mMultipleURIResponse)
- {
- result.append(LLSD("login.foo.com"));
- }
- result.append(mEvent["uri"]);
- LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
- }
- }
-
- LLBoundListener listenTo(LLEventPump& pump)
- {
- return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
- }
-
- friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
- {
- return out << "LLAresListener(" << listener.mName << ')';
- }
-};
-
class LLXMLRPCListener: public LLEventTrackable
{
std::string mName;
@@ -232,16 +177,12 @@ namespace tut
void llviewerlogin_object::test<1>()
{
DEBUG;
- // Testing login with immediate responses from Ares and XMLPRC
- // The response from both requests will come before the post request exits.
+ // Testing login with an immediate response from XMLPRC
+ // The response will come before the post request exits.
// This tests an edge case of the login state handling.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
bool respond_immediately = true;
- // Have 'dummy ares' respond immediately.
- LLAresListener dummyLLAres("dummy_llares", respond_immediately);
- dummyLLAres.listenTo(llaresPump);
// Have dummy XMLRPC respond immediately.
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
@@ -266,109 +207,12 @@ namespace tut
void llviewerlogin_object::test<2>()
{
DEBUG;
- // Tests a successful login in with delayed responses.
- // Also includes 'failure' that cause the login module
- // to re-attempt connection, once from a basic failure
- // and once from the 'indeterminate' response.
-
- set_test_name("LLLogin multiple srv uris w/ success");
-
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
-
- bool respond_immediately = false;
- bool multiple_addresses = true;
- LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
- dummyLLAres.listenTo(llaresPump);
-
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
- dummyXMLRPC.listenTo(xmlrpcPump);
-
- LLLogin login;
-
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
-
- LLSD credentials;
- credentials["first"] = "foo";
- credentials["last"] = "bar";
- credentials["passwd"] = "secret";
-
- login.connect("login.bar.com", credentials);
-
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
- // Test Authenticating State prior to first response.
- ensure_equals("Auth state 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
- ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");
-
- // First send emulated LLXMLRPCListener failure,
- // this should return login to the authenticating step and increase the attempt
- // count.
- LLSD data;
- data["status"] = "OtherError";
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Fail back to authenticate 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
- ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
-
- // Now send the 'indeterminate' response.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "indeterminate";
- data["responses"]["next_url"] = "login.indeterminate.com";
- data["responses"]["next_method"] = "test_login_method";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
- ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");
- ensure_equals("Method 3", listener.lastEvent()["data"]["request"]["method"].asString(), "test_login_method");
-
- // Finally let the auth succeed.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "true";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");
-
- login.disconnect();
-
- ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
- }
-
- template<> template<>
- void llviewerlogin_object::test<3>()
- {
- DEBUG;
// Test completed response, that fails to login.
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
-
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
dummyXMLRPC.listenTo(xmlrpcPump);
@@ -383,10 +227,6 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
// Send the failed auth request reponse
@@ -403,19 +243,15 @@ namespace tut
}
template<> template<>
- void llviewerlogin_object::test<4>()
+ void llviewerlogin_object::test<3>()
{
DEBUG;
// Test incomplete response, that end the attempt.
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
-
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
dummyXMLRPC.listenTo(xmlrpcPump);
@@ -430,10 +266,6 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
// Send the failed auth request reponse
@@ -449,17 +281,13 @@ namespace tut
}
template<> template<>
- void llviewerlogin_object::test<5>()
+ void llviewerlogin_object::test<4>()
{
DEBUG;
// Test SRV request timeout.
set_test_name("LLLogin SRV timeout testing");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
-
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
LLLogin login;
LoginListener listener("test_ear");
@@ -473,26 +301,15 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");
-
// Get the mainloop eventpump, which needs a pinging in order to drive the
// SRV timeout.
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
LLSD frame_event;
mainloop.post(frame_event);
- // In this state we have NOT sent a reply from LLAresListener -- in
- // fact there's no such object. Nonetheless, we expect the timeout to
- // have stepped the login module forward to try to authenticate with
- // the original URI.
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
- // EXT-4193: if the SRV reply isn't lost but merely late, and if it
- // arrives just at the moment we're expecting the XMLRPC reply, the
- // original code got confused and crashed. Drive that case here. We
- // observe that without the fix, this call DOES repro.
- dummyLLAres.sendReply();
}
}
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
index e889f83aa9..1bb5e95740 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -135,7 +135,7 @@ void LLUpdateChecker::Implementation::checkVersionCoro(std::string url)
LL_INFOS("checkVersionCoro") << "Getting update information from " << url << LL_ENDL;
- LLSD result = httpAdapter->getAndYield(httpRequest, url);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index f868e5cc2c..53c729469b 100755
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -26,7 +26,7 @@
#include "linden_common.h"
#include "llupdatedownloader.h"
-
+#include "httpcommon.h"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
@@ -39,7 +39,6 @@
#include "llsdserialize.h"
#include "llthread.h"
#include "llupdaterservice.h"
-#include "llcurl.h"
class LLUpdateDownloader::Implementation:
public LLThread
@@ -65,7 +64,7 @@ private:
curl_off_t mBandwidthLimit;
bool mCancelled;
LLUpdateDownloader::Client & mClient;
- CURL * mCurl;
+ LLCore::LLHttp::CURL_ptr mCurl;
LLSD mDownloadData;
llofstream mDownloadStream;
unsigned char mDownloadPercent;
@@ -192,7 +191,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client &
mBandwidthLimit(0),
mCancelled(false),
mClient(client),
- mCurl(0),
+ mCurl(),
mDownloadPercent(0),
mHeaderList(0)
{
@@ -212,10 +211,7 @@ LLUpdateDownloader::Implementation::~Implementation()
{
; // No op.
}
- if(mCurl)
- {
- LLCurl::deleteEasyHandle(mCurl);
- }
+ mCurl.reset();
}
@@ -331,9 +327,9 @@ void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)
{
if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean())
{
- llassert(mCurl != 0);
+ llassert(static_cast<bool>(mCurl));
mBandwidthLimit = bytesPerSecond;
- CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
+ CURLcode code = curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
if(code != CURLE_OK)
{
LL_WARNS("UpdaterService") << "unable to change dowload bandwidth" << LL_ENDL;
@@ -416,7 +412,7 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b
void LLUpdateDownloader::Implementation::run(void)
{
- CURLcode code = curl_easy_perform(mCurl);
+ CURLcode code = curl_easy_perform(mCurl.get());
mDownloadStream.close();
if(code == CURLE_OK)
{
@@ -460,36 +456,36 @@ void LLUpdateDownloader::Implementation::run(void)
void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)
{
- if(mCurl == 0)
+ if(!mCurl)
{
- mCurl = LLCurl::newEasyHandle();
+ mCurl = LLCore::LLHttp::createEasyHandle();
}
else
{
- curl_easy_reset(mCurl);
+ curl_easy_reset(mCurl.get());
}
- if(mCurl == 0)
+ if(!mCurl)
{
throw DownloadError("failed to initialize curl");
}
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEFUNCTION, &write_function));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEDATA, this));
if(processHeader)
{
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this));
- }
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERFUNCTION, &header_function));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERDATA, this));
+ }
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPGET, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_URL, url.c_str()));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSFUNCTION, &progress_callback));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSDATA, this));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOPROGRESS, false));
// if it's a required update set the bandwidth limit to 0 (unlimited)
curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, limit));
mDownloadPercent = 0;
}
@@ -511,7 +507,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
{
throw DownloadError("cannot add Range header");
}
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList));
mDownloadStream.open(mDownloadData["path"].asString().c_str(),
std::ios_base::out | std::ios_base::binary | std::ios_base::app);
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index c152493a51..788955a1b2 100755
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -132,6 +132,7 @@ public:
void startChecking(bool install_if_ready);
void stopChecking();
+ bool forceCheck();
bool isChecking();
LLUpdaterService::eUpdaterState getState();
@@ -266,6 +267,46 @@ void LLUpdaterServiceImpl::stopChecking()
setState(LLUpdaterService::TERMINAL);
}
+bool LLUpdaterServiceImpl::forceCheck()
+{
+ if (!mIsDownloading && getState() != LLUpdaterService::CHECKING_FOR_UPDATE)
+ {
+ if (mIsChecking)
+ {
+ // Service is running, just reset the timer
+ if (mTimer.getStarted())
+ {
+ mTimer.setTimerExpirySec(0);
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+ return true;
+ }
+ }
+ else if (!mChannel.empty() && !mVersion.empty())
+ {
+ // one time check
+ bool has_install = checkForInstall(false);
+ if (!has_install)
+ {
+ std::string query_url = LLGridManager::getInstance()->getUpdateServiceURL();
+ if (!query_url.empty())
+ {
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+ mUpdateChecker.checkVersion(query_url, mChannel, mVersion,
+ mPlatform, mPlatformVersion, mUniqueId,
+ mWillingToTest);
+ return true;
+ }
+ else
+ {
+ LL_WARNS("UpdaterService")
+ << "No updater service defined for grid '" << LLGridManager::getInstance()->getGrid() << LL_ENDL;
+ }
+ }
+ }
+ }
+ return false;
+}
+
bool LLUpdaterServiceImpl::isChecking()
{
return mIsChecking;
@@ -402,9 +443,9 @@ bool LLUpdaterServiceImpl::checkForResume()
void LLUpdaterServiceImpl::error(std::string const & message)
{
+ setState(LLUpdaterService::TEMPORARY_ERROR);
if(mIsChecking)
{
- setState(LLUpdaterService::TEMPORARY_ERROR);
restartTimer(mCheckPeriod);
}
}
@@ -449,8 +490,12 @@ void LLUpdaterServiceImpl::response(LLSD const & content)
else
{
LL_WARNS("UpdaterService") << "Invalid update query response ignored; retry in "
- << mCheckPeriod << " seconds" << LL_ENDL;
- restartTimer(mCheckPeriod);
+ << mCheckPeriod << " seconds" << LL_ENDL;
+ setState(LLUpdaterService::TEMPORARY_ERROR);
+ if (mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
}
}
@@ -672,6 +717,11 @@ void LLUpdaterService::stopChecking()
mImpl->stopChecking();
}
+bool LLUpdaterService::forceCheck()
+{
+ return mImpl->forceCheck();
+}
+
bool LLUpdaterService::isChecking()
{
return mImpl->isChecking();
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
index 0ddf24935b..95bbe1695c 100755
--- a/indra/viewer_components/updater/llupdaterservice.h
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -84,6 +84,7 @@ public:
void startChecking(bool install_if_ready = false);
void stopChecking();
+ bool forceCheck();
bool isChecking();
eUpdaterState getState();