diff --git a/pom.xml b/pom.xml
index bdcdef0..9a4ee3b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -80,6 +80,16 @@
httpclient
4.5.2
+
+ com.squareup.retrofit2
+ retrofit
+ 2.2.0
+
+
+ com.squareup.retrofit2
+ converter-gson
+ 2.2.0
+
org.apache.commons
commons-lang3
diff --git a/src/main/java/org/kontalk/xmppserver/registration/jmp/BaseResult.java b/src/main/java/org/kontalk/xmppserver/registration/jmp/BaseResult.java
new file mode 100644
index 0000000..9efcddf
--- /dev/null
+++ b/src/main/java/org/kontalk/xmppserver/registration/jmp/BaseResult.java
@@ -0,0 +1,77 @@
+/*
+ * Kontalk XMPP Tigase extension
+ * Copyright (C) 2017 Kontalk Devteam
+
+ * 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 3 of the License, 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 this program. If not, see .
+ */
+
+package org.kontalk.xmppserver.registration.jmp;
+
+
+/**
+ * Verification base result class.
+ * @author Daniele Ricci
+ */
+public abstract class BaseResult {
+
+ /**
+ * Verify was successfully submitted to the JMP service
+ */
+ public static final int STATUS_OK = 0;
+
+ /**
+ * Verify was rejected due to exceeding the maximum throughput allowed for this account.
+ * Verify can be re-requested after a short delay
+ */
+ public static final int STATUS_THROTTLED = 1;
+
+ /**
+ * Verify was rejected due to a failure within the JMP systems.
+ * Verify can be re-submitted after a short delay
+ */
+ public static final int STATUS_INTERNAL_ERROR = 2;
+
+ /**
+ * The code inserted does not match the expected value
+ */
+ public static final int STATUS_INVALID_CODE = 16;
+
+ /**
+ * There are no matching verification requests
+ */
+ public static final int STATUS_NO_RESPONSE = 101;
+
+ /**
+ * A network error occured
+ */
+ public static final int STATUS_COMMS_FAILURE = -1;
+
+ private final int status;
+ private final String errorText;
+
+ protected BaseResult(final int status,
+ final String errorText) {
+ this.status = status;
+ this.errorText = errorText;
+ }
+
+ public int getStatus() {
+ return this.status;
+ }
+
+ public String getErrorText() {
+ return this.errorText;
+ }
+
+}
diff --git a/src/main/java/org/kontalk/xmppserver/registration/jmp/CheckResult.java b/src/main/java/org/kontalk/xmppserver/registration/jmp/CheckResult.java
new file mode 100644
index 0000000..640cf3b
--- /dev/null
+++ b/src/main/java/org/kontalk/xmppserver/registration/jmp/CheckResult.java
@@ -0,0 +1,41 @@
+/*
+ * Kontalk XMPP Tigase extension
+ * Copyright (C) 2017 Kontalk Devteam
+
+ * 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 3 of the License, 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 this program. If not, see .
+ */
+
+package org.kontalk.xmppserver.registration.jmp;
+
+
+/**
+ * Verification check result.
+ * @author Daniele Ricci
+ */
+public class CheckResult extends BaseResult {
+
+ private final String eventId;
+
+ protected CheckResult(final int status,
+ final String eventId,
+ final String errorText) {
+ super(status, errorText);
+ this.eventId = eventId;
+ }
+
+ public String getEventId() {
+ return this.eventId;
+ }
+
+}
diff --git a/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClient.java b/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClient.java
new file mode 100644
index 0000000..8eda35e
--- /dev/null
+++ b/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClient.java
@@ -0,0 +1,156 @@
+/*
+ * Kontalk XMPP Tigase extension
+ * Copyright (C) 2017 Kontalk Devteam
+
+ * 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 3 of the License, 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 this program. If not, see .
+ */
+
+package org.kontalk.xmppserver.registration.jmp;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.util.Locale;
+
+
+/**
+ * Client for talking to the JMP REST interface
+ * @author Daniele Ricci
+ */
+public class JmpVerifyClient {
+ private static final Log log = LogFactory.getLog(JmpVerifyClient.class);
+
+ /**
+ * Service url used unless overridden on the constructor
+ */
+ public static final String DEFAULT_BASE_URL = "https://jvr.api.jmp.chat";
+
+ /**
+ * Default connection timeout of 5000ms used by this client unless specifically overridden onb the constructor
+ */
+ public static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
+
+ /**
+ * Default read timeout of 30000ms used by this client unless specifically overridden onb the constructor
+ */
+ public static final int DEFAULT_SO_TIMEOUT = 30000;
+
+ private final String baseUrl;
+ private final String apiKey;
+ private final String apiSecret;
+
+ private final int connectionTimeout;
+ private final int soTimeout;
+
+ private JmpVerifyService service;
+
+ public JmpVerifyClient(final String apiKey,
+ final String apiSecret) throws ParserConfigurationException {
+ this(DEFAULT_BASE_URL,
+ apiKey,
+ apiSecret,
+ DEFAULT_CONNECTION_TIMEOUT,
+ DEFAULT_SO_TIMEOUT);
+ }
+
+ /**
+ * Instanciate a new NexmoVerifyClient instance that will communicate using the supplied credentials, and will use the supplied connection and read timeout values.
+ * Additionally, you can specify an alternative service base url. For example submitting to a testing sandbox environment,
+ * or if requested to submit to an alternative address by Nexmo, for example, in cases where it may be necessary to prioritize your traffic.
+ *
+ * @param apiKey Your Nexmo account api key
+ * @param apiSecret Your Nexmo account api secret
+ * @param connectionTimeout over-ride the default connection timeout with this value (in milliseconds)
+ * @param soTimeout over-ride the default read-timeout with this value (in milliseconds)
+ */
+ public JmpVerifyClient(final String baseUrl,
+ final String apiKey,
+ final String apiSecret,
+ final int connectionTimeout,
+ final int soTimeout) throws ParserConfigurationException {
+
+ // Derive a http and a https version of the supplied base url
+ if (baseUrl == null)
+ throw new IllegalArgumentException("base url is null");
+ String url = baseUrl.trim();
+ String lc = url.toLowerCase();
+ if (!lc.startsWith("http://") && !lc.startsWith("https://"))
+ throw new IllegalArgumentException("base url does not start with http:// or https://");
+
+ this.baseUrl = url;
+ this.apiKey = apiKey;
+ this.apiSecret = apiSecret;
+ this.connectionTimeout = connectionTimeout;
+ this.soTimeout = soTimeout;
+ this.service = buildService();
+ }
+
+ public VerifyResult verify(String number, String brand) throws IOException {
+ return verify(number, brand, null, -1, null);
+ }
+
+ public VerifyResult verify(String number, String brand, String from) throws IOException {
+ return verify(number, brand, from, -1, null);
+ }
+
+ public VerifyResult verify(String number, String brand, String from, int length, Locale locale)
+ throws IOException {
+ if (number == null || brand == null)
+ throw new IllegalArgumentException("number and brand parameters are mandatory.");
+ if (length > 0 && length != 4 && length != 6)
+ throw new IllegalArgumentException("code length must be 4 or 6.");
+
+ Response response = service.verify(apiKey, apiSecret, number, brand).execute();
+ if (response.isSuccessful()) {
+ return response.body();
+ }
+ else {
+ return new VerifyResult(BaseResult.STATUS_COMMS_FAILURE, null, "Communication error");
+ }
+ }
+
+ public CheckResult check(String requestId, String code) throws IOException {
+ if (requestId == null || code == null)
+ throw new IllegalArgumentException("request ID and code parameters are mandatory.");
+
+ Response response = service.check(apiKey, apiSecret, requestId, code).execute();
+ if (response.isSuccessful()) {
+ return response.body();
+ }
+ else {
+ return new CheckResult(BaseResult.STATUS_COMMS_FAILURE, null, "Communication error");
+ }
+ }
+
+ private JmpVerifyService buildService() {
+ Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .create();
+
+ return new Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build()
+ .create(JmpVerifyService.class);
+ }
+
+}
diff --git a/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyService.java b/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyService.java
new file mode 100644
index 0000000..0c18d41
--- /dev/null
+++ b/src/main/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyService.java
@@ -0,0 +1,36 @@
+/*
+ * Kontalk XMPP Tigase extension
+ * Copyright (C) 2017 Kontalk Devteam
+
+ * 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 3 of the License, 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 this program. If not, see .
+ */
+
+package org.kontalk.xmppserver.registration.jmp;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+
+public interface JmpVerifyService {
+
+ @GET("verify")
+ Call verify(@Query("api_key") String apiKey, @Query("api_secret") String apiSecret,
+ @Query("number") String number, @Query("brand") String brand);
+
+ @GET("verify/check")
+ Call check(@Query("api_key") String apiKey, @Query("api_secret") String apiSecret,
+ @Query("request_id") String requestId, @Query("code") String code);
+
+}
diff --git a/src/main/java/org/kontalk/xmppserver/registration/jmp/VerifyResult.java b/src/main/java/org/kontalk/xmppserver/registration/jmp/VerifyResult.java
new file mode 100644
index 0000000..ce32ed7
--- /dev/null
+++ b/src/main/java/org/kontalk/xmppserver/registration/jmp/VerifyResult.java
@@ -0,0 +1,41 @@
+/*
+ * Kontalk XMPP Tigase extension
+ * Copyright (C) 2017 Kontalk Devteam
+
+ * 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 3 of the License, 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 this program. If not, see .
+ */
+
+package org.kontalk.xmppserver.registration.jmp;
+
+
+/**
+ * Verification request result.
+ * @author Daniele Ricci
+ */
+public class VerifyResult extends BaseResult {
+
+ private final String requestId;
+
+ protected VerifyResult(final int status,
+ final String requestId,
+ final String errorText) {
+ super(status, errorText);
+ this.requestId = requestId;
+ }
+
+ public String getRequestId() {
+ return this.requestId;
+ }
+
+}
diff --git a/src/test/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClientTest.java b/src/test/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClientTest.java
new file mode 100644
index 0000000..9233bb0
--- /dev/null
+++ b/src/test/java/org/kontalk/xmppserver/registration/jmp/JmpVerifyClientTest.java
@@ -0,0 +1,48 @@
+package org.kontalk.xmppserver.registration.jmp;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class JmpVerifyClientTest {
+
+ private static final String API_KEY = null;
+ private static final String API_SECRET = null;
+
+ // insert values here to execute a verify test
+ private static final String TEST_NUMBER = null;
+ private static final String TEST_BRAND = null;
+ // insert values here to execute a verify check test
+ private static final String TEST_REQUEST_ID = null;
+ private static final String TEST_CODE = null;
+
+ private JmpVerifyClient client;
+
+ @Before
+ public void setUp() throws Exception {
+ client = new JmpVerifyClient(API_KEY, API_SECRET);
+ }
+
+ private void assertStatus(BaseResult res) {
+ assertEquals(BaseResult.STATUS_OK, res.getStatus());
+ }
+
+ @Test
+ public void testRequest() throws Exception {
+ if (TEST_NUMBER != null && TEST_BRAND != null) {
+ VerifyResult res = client.verify(TEST_NUMBER, TEST_BRAND);
+ System.out.println(res.getRequestId());
+ assertStatus(res);
+ }
+ }
+
+ @Test
+ public void testCheck() throws Exception {
+ if (TEST_REQUEST_ID != null && TEST_CODE != null) {
+ CheckResult res = client.check(TEST_REQUEST_ID, TEST_CODE);
+ assertStatus(res);
+ }
+ }
+}