Merge pull request #2049 from DoraXBMC/master
authorSascha Montellese <sascha.montellese@gmail.com>
Fri, 9 Aug 2013 07:31:24 +0000 (00:31 -0700)
committerSascha Montellese <sascha.montellese@gmail.com>
Fri, 9 Aug 2013 07:31:24 +0000 (00:31 -0700)
Adding profiles support to the JSON-RPC and to the default web server.

13 files changed:
addons/webinterface.default/addon.xml
addons/webinterface.default/css/core.css
addons/webinterface.default/index.html
addons/webinterface.default/js/MediaLibrary.js
project/VS2010Express/XBMC.vcxproj
project/VS2010Express/XBMC.vcxproj.filters
xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
xbmc/interfaces/json-rpc/Makefile
xbmc/interfaces/json-rpc/ProfilesOperations.cpp [new file with mode: 0644]
xbmc/interfaces/json-rpc/ProfilesOperations.h [new file with mode: 0644]
xbmc/interfaces/json-rpc/ServiceDescription.h
xbmc/interfaces/json-rpc/methods.json
xbmc/interfaces/json-rpc/types.json

index c70f185..f6476be 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <addon
   id="webinterface.default"
-  version="2.1.11"
+  version="2.2.0"
   name="Default"
   provider-name="Team XBMC">
   <requires>
index df44c4a..c9814cf 100755 (executable)
@@ -75,7 +75,8 @@ body {
        padding: 10px 10px 15px 10px;
        }
 
-.floatableMovieCover {
+.floatableMovieCover,
+.floatableProfileThumb {
        float: left;
        width: 130px;
        height: 200px;
@@ -84,7 +85,8 @@ body {
 
 .floatableAlbum:hover,
 .floatableTVShowCover:hover,
-.floatableMovieCover:hover {
+.floatableMovieCover:hover,
+.floatableProfileThumb:hover {
        background: #aeaeae;
        }
 
@@ -119,12 +121,14 @@ body {
 
 #libraryContainer .floatableAlbum,
 #movieLibraryContainer .floatableMovieCover,
+#profilesContainer .floatableProfileThumb,
 #tvshowLibraryContainer .floatableTVShowCover {
        cursor: pointer;
        }
 
 .floatableAlbum div.imgWrapper,
 .floatableMovieCover div.imgWrapper,
+.floatableProfileThumb div.imgWrapper,
 .floatableTVShowCover div.imgWrapper {
        width: 130px;
        height: 130px;
@@ -147,7 +151,9 @@ div.imgWrapper div.inner {
        }
 
 .floatableMovieCover div.imgWrapper,
-.floatableMovieCover div.imgWrapper div.inner {
+.floatableMovieCover div.imgWrapper div.inner,
+.floatableProfileThumb div.imgWrapper,
+.floatableProfileThumb div.imgWrapper div.inner {
        height: 190px;
        }
 
@@ -176,12 +182,14 @@ div.imgWrapper div.inner {
        width: 130px;
        }
 
-.floatableMovieCover img {
+.floatableMovieCover img,
+.floatableProfileThumb img {
        height: 180px;
        }
 
 .floatableAlbum p.album,
-.floatableMovieCover p.album {
+.floatableMovieCover p.album,
+.floatableProfileThumb p.album {
        font-size: 12px;
        font-weight: 700;
        color: #000;
@@ -194,7 +202,8 @@ div.imgWrapper div.inner {
        }
 
 .floatableAlbum p.artist,
-.floatableMovieCover p.artist {
+.floatableMovieCover p.artist,
+.floatableProfileThumb p.artist {
        font-size: 11px;
        color: #777;
        text-align: center;
index 9b3a7be..df3a561 100755 (executable)
@@ -17,6 +17,7 @@
       <div id="commsErrorPanel" style="display: none;"></div>
       <div id="navigation">
         <ul>
+          <li id="profiles">Profiles</li>
           <li id="remoteControl">Remote</li>
           <li id="movieLibrary">Movies</li>
           <li id="tvshowLibrary">TV Shows</li>
index 5731eb3..916c418 100755 (executable)
@@ -32,6 +32,7 @@ MediaLibrary.prototype = {
     $('#tvshowLibrary').click(jQuery.proxy(this.tvshowLibraryOpen, this));
     $('#pictureLibrary').click(jQuery.proxy(this.pictureLibraryOpen, this));
     $('#remoteControl').click(jQuery.proxy(this.remoteControlOpen, this));
+    $('#profiles').click(jQuery.proxy(this.profilesOpen, this));
     $('#overlay').click(jQuery.proxy(this.hideOverlay, this));
     $(window).resize(jQuery.proxy(this.updatePlayButtonLocation, this));
     $(document).on('keydown', jQuery.proxy(this.handleKeyPress, this));
@@ -43,6 +44,7 @@ MediaLibrary.prototype = {
     $('#tvshowLibrary').removeClass('selected');
     $('#remoteControl').removeClass('selected');
     $('#pictureLibrary').removeClass('selected');
+    $('#profilesLibrary').removeClass('selected');
     this.hideOverlay();
   },
   replaceAll: function (haystack, needle, thread) {
@@ -329,6 +331,10 @@ MediaLibrary.prototype = {
         className = 'floatableAlbum';
         code = '<p class="album" title="' + title + '">' + showTitle + '</p>';
         break;
+      case 'profile':
+        className = 'floatableProfileThumb';
+        code = '<p class="album" title="' + title + '">' + showTitle + '</p>';
+        break;
     }
     return floatableAlbum.addClass(className).html('<div class="imgWrapper"><div class="inner"><img src="' + path + '" alt="' + title + '" /></div></div>' + code);
   },
@@ -747,6 +753,15 @@ MediaLibrary.prototype = {
       }
     });
   },
+  loadProfile: function (event) {
+    return xbmc.rpc.request({
+      'context': this,
+      'method': 'Profiles.LoadProfile',
+        'params': {
+          'profile': event.data.profile.label
+        }
+    });
+  },
   movieLibraryOpen: function () {
     this.resetPage();
     $('#movieLibrary').addClass('selected');
@@ -891,6 +906,73 @@ MediaLibrary.prototype = {
       libraryContainer.trigger('scroll');
     }
   },
+  profilesOpen: function () {
+    this.resetPage();
+    $('#profiles').addClass('selected');
+    $('.contentContainer').hide();
+    var libraryContainer = $('#profilesContainer');
+    if (!libraryContainer || libraryContainer.length == 0) {
+      $('#spinner').show();
+      var currentProfile = "";
+      xbmc.rpc.request({
+          'method': 'Profiles.GetCurrentProfile',
+              'params': {
+                  'properties': [
+                      'lockmode'
+                   ]
+               },
+          'success': function (data) {
+              if (data)
+                  if (data.result)
+                      currentProfile = data.result.label;
+          }
+      });
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'Profiles.GetProfiles',
+        'params': {
+          'limits': {
+            'start': 0
+          },
+          'properties': [
+            'thumbnail'
+          ],
+          'sort': {
+            'method': 'sorttitle',
+            'ignorearticle': true
+          }
+        },
+        'success': function (data) {
+          if (data && data.result && data.result.profiles) {
+            libraryContainer = $('<div>');
+            libraryContainer.attr('id', 'profilesContainer')
+                      .addClass('contentContainer');
+            $('#content').append(libraryContainer);
+          } else {
+            libraryContainer.html('');
+          }
+          $.each($(data.result.profiles), jQuery.proxy(function (i, item) {
+            var itemLabel = item.label;
+            if (currentProfile == itemLabel)
+            {
+              itemLabel = itemLabel + "*";
+            }
+            var floatableProfileThumb = this.generateThumb('profile', item.thumbnail, itemLabel);
+            floatableProfileThumb.bind('click', { profile: item }, jQuery.proxy(this.loadProfile, this));
+            libraryContainer.append(floatableProfileThumb);
+          }, this));
+          libraryContainer.append($('<div>').addClass('footerPadding'));
+          $('#spinner').hide();
+          libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
+          libraryContainer.trigger('scroll');
+          myScroll = new iScroll('profilesContainer');
+        }
+      });
+    } else {
+      libraryContainer.show();
+      libraryContainer.trigger('scroll');
+    }
+  },
   updateScrollEffects: function (event) {
     if (event.data.activeLibrary && $(event.data.activeLibrary).scrollTop() > 0) {
       $('#topScrollFade').fadeIn();
index acd84b6..46f51df 100644 (file)
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\JSONServiceDescription.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\PlayerOperations.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\PlaylistOperations.cpp" />
+    <ClCompile Include="..\..\xbmc\interfaces\json-rpc\ProfilesOperations.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\PVROperations.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\SystemOperations.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\VideoLibrary.cpp" />
     <ClInclude Include="..\..\xbmc\interfaces\generic\LanguageInvokerThread.h" />
     <ClInclude Include="..\..\xbmc\interfaces\generic\ScriptInvocationManager.h" />
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\FavouritesOperations.h" />
+    <ClInclude Include="..\..\xbmc\interfaces\json-rpc\ProfilesOperations.h" />
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\PVROperations.h" />
     <ClInclude Include="..\..\xbmc\interfaces\legacy\Addon.h" />
     <ClInclude Include="..\..\xbmc\interfaces\legacy\AddonCallback.h" />
     </VisualStudio>
   </ProjectExtensions>
   <Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project>
\ No newline at end of file
+</Project>
index da231f7..272f2c7 100644 (file)
     <ClCompile Include="..\..\xbmc\addons\AddonCallbacksCodec.cpp">
       <Filter>addons</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\xbmc\interfaces\json-rpc\ProfilesOperations.cpp">
+      <Filter>interfaces\json-rpc</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\xbmc\GitRevision.cpp" />
     <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAE.cpp">
       <Filter>cores\AudioEngine\Engines\ActiveAE</Filter>
     <ClInclude Include="..\..\xbmc\addons\AddonCallbacksCodec.h">
       <Filter>addons</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\xbmc\interfaces\json-rpc\ProfilesOperations.h">
+      <Filter>interfaces\json-rpc</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\xbmc\win32\PlatformInclude.h" />
     <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAE.h">
       <Filter>cores\AudioEngine\Engines\ActiveAE</Filter>
       <Filter>interfaces\swig</Filter>
     </None>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index 074c2da..bc79a92 100644 (file)
@@ -36,6 +36,7 @@
 #include "XBMCOperations.h"
 #include "ApplicationOperations.h"
 #include "PVROperations.h"
+#include "ProfilesOperations.h"
 #include "FavouritesOperations.h"
 
 using namespace std;
@@ -163,6 +164,11 @@ JsonRpcMethodMap CJSONServiceDescription::m_methodMaps[] = {
   { "PVR.Record",                                   CPVROperations::Record },
   { "PVR.Scan",                                     CPVROperations::Scan },
 
+// Profiles operations
+  { "Profiles.GetProfiles",                         CProfilesOperations::GetProfiles},
+  { "Profiles.GetCurrentProfile",                   CProfilesOperations::GetCurrentProfile},
+  { "Profiles.LoadProfile",                         CProfilesOperations::LoadProfile},
+
 // System operations
   { "System.GetProperties",                         CSystemOperations::GetProperties },
   { "System.EjectOpticalDrive",                     CSystemOperations::EjectOpticalDrive },
index 6dc3ae6..398effb 100644 (file)
@@ -10,6 +10,7 @@ SRCS=AddonsOperations.cpp \
      JSONServiceDescription.cpp \
      PlayerOperations.cpp \
      PlaylistOperations.cpp \
+     ProfilesOperations.cpp \
      PVROperations.cpp \
      SystemOperations.cpp \
      VideoLibrary.cpp \
diff --git a/xbmc/interfaces/json-rpc/ProfilesOperations.cpp b/xbmc/interfaces/json-rpc/ProfilesOperations.cpp
new file mode 100644 (file)
index 0000000..3edb628
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *      Copyright (C) 2013 Team XBMC
+ *      http://xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ProfilesOperations.h"
+#include "ApplicationMessenger.h"
+#include "guilib/LocalizeStrings.h"
+#include "profiles/ProfilesManager.h"
+#include "utils/md5.h"
+
+using namespace JSONRPC;
+
+JSONRPC_STATUS CProfilesOperations::GetProfiles(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+  CFileItemList listItems;
+
+  for (unsigned int i = 0; i < CProfilesManager::Get().GetNumberOfProfiles(); ++i)
+  {
+    const CProfile *profile = CProfilesManager::Get().GetProfile(i);
+    CFileItemPtr item(new CFileItem(profile->getName()));
+    item->SetArt("thumb", profile->getThumb());
+    listItems.Add(item);
+  }
+
+  HandleFileItemList("profileid", false, "profiles", listItems, parameterObject, result);
+
+  for (CVariant::const_iterator_array propertyiter = parameterObject["properties"].begin_array(); propertyiter != parameterObject["properties"].end_array(); ++propertyiter)
+  {
+    if (propertyiter->isString() &&
+        propertyiter->asString() == "lockmode")
+    {
+      for (CVariant::iterator_array profileiter = result["profiles"].begin_array(); profileiter != result["profiles"].end_array(); ++profileiter)
+      {
+        CStdString profilename = (*profileiter)["label"].asString();
+        int index = CProfilesManager::Get().GetProfileIndex(profilename);
+        const CProfile *profile = CProfilesManager::Get().GetProfile(index);
+        LockType locktype = LOCK_MODE_UNKNOWN;
+        if (index == 0)
+          locktype = CProfilesManager::Get().GetMasterProfile().getLockMode();
+        else
+          locktype = profile->getLockMode();
+        (*profileiter)["lockmode"] = locktype;
+      }
+      break;
+    }
+  }
+  return OK;
+}
+
+JSONRPC_STATUS CProfilesOperations::GetCurrentProfile(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+  const CProfile& currentProfile = CProfilesManager::Get().GetCurrentProfile();
+  CVariant profileVariant = CVariant(CVariant::VariantTypeObject);
+  profileVariant["label"] = currentProfile.getName();
+  for (CVariant::const_iterator_array propertyiter = parameterObject["properties"].begin_array(); propertyiter != parameterObject["properties"].end_array(); ++propertyiter)
+  {
+    if (propertyiter->isString())
+    {
+      if (propertyiter->asString() == "lockmode")
+        profileVariant["lockmode"] = currentProfile.getLockMode();
+      else if (propertyiter->asString() == "thumbnail")
+        profileVariant["thumbnail"] = currentProfile.getThumb();
+    }
+  }
+
+  result = profileVariant;
+
+  return OK;
+}
+
+JSONRPC_STATUS CProfilesOperations::LoadProfile(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+  CStdString profilename = parameterObject["profile"].asString();
+  int index = CProfilesManager::Get().GetProfileIndex(profilename);
+  
+  if (index < 0)
+    return InvalidParams;
+
+       // Init prompt
+       bool bPrompt = false;
+       bPrompt = parameterObject["prompt"].asBoolean();
+    
+       bool bCanceled;
+  bool bLoadProfile(false);
+
+  if (CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||            // Password not needed
+      (bPrompt && g_passwordManager.IsProfileLockUnlocked(index, bCanceled, bPrompt)))  // Password needed and user asked to enter it
+    bLoadProfile = true;
+       else if (!bCanceled && parameterObject.isMember("password"))  // Password needed and user provided it
+       {
+    const CVariant &passwordObject = parameterObject["password"];
+         CStdString strToVerify;  // Holds user saved password hash
+               if (index == 0)
+                 strToVerify = CProfilesManager::Get().GetMasterProfile().getLockCode();
+               else
+               {
+           CProfile *profile = CProfilesManager::Get().GetProfile(index);
+                 strToVerify = profile->getLockCode();
+               }
+
+               CStdString password = passwordObject["value"].asString();
+               
+               // Create password hash from the provided password if md5 is not used
+    CStdString md5pword2;
+    CStdString encryption = passwordObject["encryption"].asString();
+    if (encryption.Equals("none"))
+               {
+                       XBMC::XBMC_MD5 md5state;
+                       md5state.append(password);
+                       md5state.getDigest(md5pword2);
+               }
+               else if (encryption.Equals("md5"))
+                       md5pword2 = password;
+
+               // Verify profided password
+    if (strToVerify.Equals(md5pword2))
+                 bLoadProfile = true;
+       }
+
+  if (bLoadProfile)
+  {
+    CApplicationMessenger::Get().LoadProfile(index);
+    return ACK;
+  }
+  return InvalidParams;
+}
diff --git a/xbmc/interfaces/json-rpc/ProfilesOperations.h b/xbmc/interfaces/json-rpc/ProfilesOperations.h
new file mode 100644 (file)
index 0000000..360a747
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+/*
+ *      Copyright (C) 2013 Team XBMC
+ *      http://xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "utils/StdString.h"
+#include "JSONRPC.h"
+#include "FileItemHandler.h"
+
+namespace JSONRPC
+{
+  class CProfilesOperations : CFileItemHandler
+  {
+  public:
+    static JSONRPC_STATUS GetProfiles(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+    static JSONRPC_STATUS GetCurrentProfile(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+    static JSONRPC_STATUS LoadProfile(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+  };
+}
index 499902e..7f5591d 100644 (file)
@@ -22,7 +22,7 @@
 namespace JSONRPC
 {
   const char* const JSONRPC_SERVICE_ID          = "http://www.xbmc.org/jsonrpc/ServiceDescription.json";
-  const char* const JSONRPC_SERVICE_VERSION     = "6.5.3";
+  const char* const JSONRPC_SERVICE_VERSION     = "6.6.0";
   const char* const JSONRPC_SERVICE_DESCRIPTION = "JSON-RPC API of XBMC";
 
   const char* const JSONRPC_SERVICE_TYPES[] = {  
@@ -807,7 +807,25 @@ namespace JSONRPC
         "}"
       "}"
     "}",
-    "\"List.Filter.Rule\": {"
+    "\"Profiles.Password\": {"
+      "\"type\": \"object\","
+      "\"properties\": {"
+        "\"value\": { \"type\": \"string\", \"required\": true, \"description\": \"Password\" },"
+        "\"encryption\": { \"type\": \"string\", \"description\": \"Password Encryption\", \"default\": \"md5\", \"enum\": [ \"none\", \"md5\" ] }"
+      "}"
+    "}",
+    "\"Profiles.Fields.Profile\": {"
+      "\"extends\": \"Item.Fields.Base\","
+      "\"items\": { \"type\": \"string\", \"enum\": [ \"thumbnail\", \"lockmode\" ] }"
+    "}",
+         "\"Profiles.Details.Profile\": {"
+      "\"extends\": \"Item.Details.Base\","
+      "\"properties\": {"
+        "\"thumbnail\": { \"type\": \"string\" },"
+        "\"lockmode\": { \"type\": \"integer\" }"
+      "}"
+    "}",
+         "\"List.Filter.Rule\": {"
       "\"type\": \"object\","
       "\"properties\": {"
         "\"operator\": { \"$ref\": \"List.Filter.Operators\", \"required\": true },"
@@ -2934,6 +2952,48 @@ namespace JSONRPC
       "\"params\": [ ],"
       "\"returns\":  \"string\""
     "}",
+    "\"Profiles.GetProfiles\": {"
+      "\"type\": \"method\","
+      "\"description\": \"Retrieve all profiles\","
+      "\"transport\": \"Response\","
+      "\"permission\": \"ReadData\","
+      "\"params\": ["
+        "{ \"name\": \"properties\", \"$ref\": \"Profiles.Fields.Profile\" },"
+        "{ \"name\": \"limits\", \"$ref\": \"List.Limits\" },"
+        "{ \"name\": \"sort\", \"$ref\": \"List.Sort\" }"
+      "],"
+      "\"returns\": {"
+        "\"type\": \"object\","
+        "\"properties\": {"
+          "\"limits\": { \"$ref\": \"List.LimitsReturned\", \"required\": true },"
+          "\"profiles\": { \"type\": \"array\", \"required\": true,"
+           "\"items\": { \"$ref\": \"Profiles.Details.Profile\" }"
+          "}"
+        "}"
+      "}"
+    "}",
+    "\"Profiles.GetCurrentProfile\": {"
+      "\"type\": \"method\","
+      "\"description\": \"Retrieve the current profile\","
+      "\"transport\": \"Response\","
+      "\"permission\": \"ReadData\","
+      "\"params\": ["
+        "{ \"name\": \"properties\", \"$ref\": \"Profiles.Fields.Profile\" }"
+      "],"
+      "\"returns\":  { \"$ref\": \"Profiles.Details.Profile\", \"required\": true }"
+    "}",
+    "\"Profiles.LoadProfile\": {"
+      "\"type\": \"method\","
+      "\"description\": \"Load the specified profile\","
+      "\"transport\": \"Response\","
+      "\"permission\": \"Navigate\","
+      "\"params\": ["
+        "{ \"name\": \"profile\", \"type\": \"string\", \"required\": true, \"description\": \"Profile name\" },"
+        "{ \"name\": \"prompt\", \"type\": \"boolean\", \"description\": \"Prompt for password\" },"
+        "{ \"name\": \"password\", \"$ref\": \"Profiles.Password\" }"
+      "],"
+      "\"returns\": \"string\""
+    "}",
     "\"System.GetProperties\": {"
       "\"type\": \"method\","
       "\"description\": \"Retrieves the values of the given properties\","
index f8a551c..627c32a 100644 (file)
     "params": [ ],
     "returns":  "string"
   },
+  "Profiles.GetProfiles": {
+    "type": "method",
+    "description": "Retrieve all profiles",
+    "transport": "Response",
+    "permission": "ReadData",
+    "params": [
+      { "name": "properties", "$ref": "Profiles.Fields.Profile" },
+      { "name": "limits", "$ref": "List.Limits" },
+      { "name": "sort", "$ref": "List.Sort" }"
+    ],
+    "returns": {
+      "type": "object",
+      "properties": {
+        "limits": { "$ref": "List.LimitsReturned", "required": true },
+        "profiles": { "type": "array", "required": true,
+          "items": { "$ref": "Profiles.Details.Profile" }
+        }
+      }
+    }
+  },
+  "Profiles.GetCurrentProfile": {
+    "type": "method",
+    "description": "Retrieve the current profile",
+    "transport": "Response",
+    "permission": "ReadData",
+    "params": [
+      { "name": "properties", "$ref": "Profiles.Fields.Profile" }
+    ],
+       "returns":  { "$ref": "Profiles.Details.Profile", "required": true }
+  },
+  "Profiles.LoadProfile": {
+    "type": "method",
+    "description": "Load the specified profile",
+    "transport": "Response",
+    "permission": "Navigate",
+    "params": [
+      { "name": "profile", "type": "string", "required": true, "description": "Profile name" },
+      { "name": "prompt", "type": "boolean", "description": "Prompt for password" },
+      { "name": "password", "$ref": "Profiles.Password" }
+    ],
+    "returns": "string"
+  },
   "System.GetProperties": {
     "type": "method",
     "description": "Retrieves the values of the given properties",
index 2c6d622..3e30b09 100644 (file)
       }
     }
   },
+  "Profiles.Password": {
+    "type": "object",
+    "properties": {
+      "value": { "type": "string", "required": true, "description": "Password" },
+      "encryption": { "type": "string", "description": "Password Encryption", "default": "md5", "enum": [ "none", "md5" ] }
+    }
+  },
+  "Profiles.Fields.Profile": {
+    "extends": "Item.Fields.Base",
+    "items": { "type": "string", "enum": [ "thumbnail", "lockmode" ] }
+  },
+  "Profiles.Details.Profile": {
+    "extends": "Item.Details.Base",
+    "properties": {
+      "thumbnail": { "type": "string" },
+      "lockmode": { "type": "integer" }
+    }
+  },
   "List.Filter.Rule": {
     "type": "object",
     "properties": {