Merge pull request #7 in MM/mpin-sdk-core from feature/slav_maas_workflow to master

* commit '67c800f5884009a2981b13b5e1def3417becfeff':
  Add support for the MaaS workflow
diff --git a/src/json/reader.inl b/src/json/reader.inl
index 9211675..313e5cb 100644
--- a/src/json/reader.inl
+++ b/src/json/reader.inl
@@ -303,8 +303,7 @@
 }
 
 static void ConsumeUnicode(std::istream& str, std::vector<utf8::uint16_t>& uni16) {
-    char bytes[4];
-    memset(bytes, 0, sizeof(bytes));
+    char bytes[4] = { '\0' };
     str.get(bytes[0]);
     str.get(bytes[1]);
     str.get(bytes[2]);
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index 3f94c73..c9a17f6 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -970,7 +970,7 @@
     return Status::OK;
 }
 
-Status MPinSDK::StartAuthentication(INOUT UserPtr user)
+Status MPinSDK::StartAuthentication(INOUT UserPtr user, const String& accessCode)
 {
     Status s = CheckIfBackendIsSet();
     if(s != Status::OK)
@@ -985,6 +985,16 @@
         return s;
     }
 
+    String codeStatusURL = m_clientSettings.GetStringParam("codeStatusURL");
+    if(!codeStatusURL.empty() && !accessCode.empty())
+    {
+        util::JsonObject data;
+        data["status"] = json::String("user");
+        data["wid"] = json::String(accessCode);
+        data["user"] = json::String(user->GetId());
+        MakeRequest(codeStatusURL, IHttpRequest::POST, data);
+    }
+
     bool useTimePermits = m_clientSettings.GetBoolParam("usePermits", true);
     if(!useTimePermits)
     {
@@ -1322,6 +1332,33 @@
     return calculatedCheckSum == checkSum;
 }
 
+String MPinSDK::GetPrerollUserId(const String& accessCode)
+{
+    Status s = CheckIfBackendIsSet();
+    if(s != Status::OK)
+    {
+        return "";
+    }
+
+    String codeStatusUrl = m_clientSettings.GetStringParam("codeStatusURL");
+    if(codeStatusUrl.empty())
+    {
+        return "";
+    }
+
+    util::JsonObject data;
+    data["status"] = json::String("wid");
+    data["wid"] = json::String(accessCode);
+
+    HttpResponse response = MakeRequest(codeStatusUrl, IHttpRequest::POST, data);
+    if(response.GetStatus() != HttpResponse::HTTP_OK)
+    {
+        return "";
+    }
+
+    return response.GetJsonData().GetStringParam("prerollId");
+}
+
 void MPinSDK::DeleteUser(UserPtr user)
 {
     UsersMap::iterator i = m_users.find(user->GetId());
@@ -1338,16 +1375,35 @@
     m_logoutData.erase(user);
 }
 
-void MPinSDK::ListUsers(std::vector<UserPtr>& users) const
+Status MPinSDK::ListUsers(std::vector<UserPtr>& users) const
 {
+    Status s = CheckIfBackendIsSet();
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     ListUsers(users, m_users);
+    return Status::OK;
 }
 
-void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const
+Status MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const
 {
+    Status s = CheckIfIsInitialized();
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     UsersMap usersMap;
-    LoadUsersFromStorage(backend, usersMap);
+    s = LoadUsersFromStorage(backend, usersMap);
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     ListUsers(users, usersMap);
+    return Status::OK;
 }
 
 void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const UsersMap& usersMap) const
@@ -1561,15 +1617,21 @@
 	return Status(Status::OK);
 }
 
-void MPinSDK::ListBackends(OUT std::vector<String>& backends) const
+Status MPinSDK::ListBackends(OUT std::vector<String>& backends) const
 {
-	IStorage* storage = m_context->GetStorage(IStorage::NONSECURE);
+    Status s = CheckIfIsInitialized();
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
+    IStorage* storage = m_context->GetStorage(IStorage::NONSECURE);
 	String data;
 	storage->GetData(data);
     data.Trim();
 	if(data.empty())
     {
-		return;
+		return Status::OK;
 	}
 
 	try
@@ -1583,7 +1645,12 @@
             backends.push_back(i->name);
         }
     }
-    catch(const json::Exception&) {}
+    catch(const json::Exception& e)
+    {
+        return Status(Status::STORAGE_ERROR, e.what());
+    }
+
+    return Status::OK;
 }
 
 const char * MPinSDK::GetVersion()
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index 902189a..ec69d58 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -236,17 +236,19 @@
     Status ConfirmRegistration(INOUT UserPtr user, const String& pushMessageIdentifier = "");
     Status FinishRegistration(INOUT UserPtr user, const String& pin);
 
-    Status StartAuthentication(INOUT UserPtr user);
+    Status StartAuthentication(INOUT UserPtr user, const String& accessCode = "");
     Status CheckAccessNumber(const String& accessNumber);
     Status FinishAuthentication(INOUT UserPtr user, const String& pin);
     Status FinishAuthentication(INOUT UserPtr user, const String& pin, OUT String& authResultData);
     Status FinishAuthenticationOTP(INOUT UserPtr user, const String& pin, OUT OTP& otp);
     Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);
 
+    String GetPrerollUserId(const String& accessCode);
+
     void DeleteUser(INOUT UserPtr user);
-    void ListUsers(OUT std::vector<UserPtr>& users) const;
-    void ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;
-    void ListBackends(OUT std::vector<String>& backends) const;
+    Status ListUsers(OUT std::vector<UserPtr>& users) const;
+    Status ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;
+    Status ListBackends(OUT std::vector<String>& backends) const;
     const char * GetVersion();
     bool CanLogout(IN UserPtr user);
     bool Logout(IN UserPtr user);
diff --git a/src/version.h b/src/version.h
index fc4b9bd..a9b268d 100644
--- a/src/version.h
+++ b/src/version.h
@@ -25,6 +25,6 @@
 #define _MPIN_SDK_VERSION_H_
 
 #define MPIN_SDK_VERSION "1.0.0"
-#define MPIN_SDK_V2_VERSION "2.0.0"
+#define MPIN_SDK_V2_VERSION "2.1.0"
 
 #endif // _MPIN_SDK_VERSION_H_
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index 6957afd..685a37a 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -27,7 +27,10 @@
 #include "contexts/cmdline_context.h"
 #include "CvLogger.h"
 
-using namespace std;
+using std::cout;
+using std::cin;
+using std::endl;
+using std::vector;
 
 struct Backend
 {
@@ -78,6 +81,13 @@
         TestBackend(sdk, backends[i].backend, backends[i].rpsPrefix);
     }
 
+    bool testMaasWorkflow = false;
+    const char *maasBackend = "http://192.168.98.141:8001";
+    if(testMaasWorkflow)
+    {
+        s = sdk.SetBackend(maasBackend);
+    }
+
     //s = sdk.SetBackend(backends[1].backend, backends[1].rpsPrefix);
     if(s != MPinSDK::Status::OK)
     {
@@ -146,7 +156,16 @@
         _getch();
     }
 
-    s = sdk.StartAuthentication(user);
+    MPinSDK::String accessCode;
+    if(testMaasWorkflow)
+    {
+        cout << "Enter access code: ";
+        cin >> accessCode;
+        MPinSDK::String userId = sdk.GetPrerollUserId(accessCode);
+        cout << "GetPrerollUserId() returned '" << userId << "'. Press any key to continue..." << endl;
+    }
+
+    s = sdk.StartAuthentication(user, accessCode);
     if(s != MPinSDK::Status::OK)
     {
         cout << "Failed to start user authentication: status code = " << s.GetStatusCode() << ", error: " << s.GetErrorMessage() << endl;
@@ -160,7 +179,14 @@
     cin >> pin;
 
     MPinSDK::String authData;
-    s = sdk.FinishAuthentication(user, pin, authData);
+    if(!testMaasWorkflow)
+    {
+        s = sdk.FinishAuthentication(user, pin, authData);
+    }
+    else
+    {
+        s = sdk.FinishAuthenticationAN(user, pin, accessCode);
+    }
     if(s != MPinSDK::Status::OK)
     {
         cout << "Failed to authenticate user: status code = " << s.GetStatusCode() << ", error: " << s.GetErrorMessage() << endl;