OF-1194: New SMS service

This commit introduces a new SMS service that takes after the
existing email service. The new service utilizes SMPP to allow
for messages to be sent to a suitable service provider.
parent 0b0dc85e
......@@ -54,6 +54,7 @@ jmdns.jar | PRE 1.0, patched
jmock.jar | 2.1.0 |
jmock-junit4.jar | 2.1.0 |
jmock-legacy.jar | 2.1.0 |
jsmpp | 2.2.4 | Apache 2.0
jtds.jar | 1.3.1 | LGPL
junit.jar | 4.11 | EPL 1.0
hamcrest-core.jar | 1.3 (required by junit) | new BSD licence
......
......@@ -496,6 +496,8 @@ tab.server.descr=Click to manage server settings
sidebar.manage-updates.descr=Click to manage server or plugins updates
sidebar.server-email=Email Settings
sidebar.server-email.descr=Click to configure email settings
sidebar.server-sms=SMS Settings
sidebar.server-sms.descr=Click to configure SMS settings
sidebar.security-audit-viewer=Security Audit Viewer
sidebar.security-audit-viewer.descr=Click to view the security audit logs
sidebar.sidebar-server-settings=Server Settings
......@@ -2650,6 +2652,43 @@ system.emailtest.body=Body
system.emailtest.send=Send
system.emailtest.cancel=Cancel/Go Back
# System SMS
system.sms.title=SMS Settings
system.sms.info=Use the form below to configure the connection to your SMS server. The SMPP protocol will be used to \
establish a connection. At a minimum, you should provide the host address of the SMPP server, your systemId \
(which can be thought of as your username) the corresponding password and an optional system type, all of \
which should be supplied to you by your SMPP service provider.
system.sms.update_success=Settings updated successfully.
system.sms.config_failure=Configuration failure. Please verify that you have filled out all required fields \
correctly and try again.
system.sms.name=SMPP Settings
system.sms.host=Host Address
system.sms.valid_host=Please enter a valid host address.
system.sms.port=Port (Optional)
system.sms.valid_port=Please enter a valid port number (between 1 and 65535).
system.sms.systemId=SystemId (username)
system.sms.valid_systemId=Please enter a valid systemId value.
system.sms.password=Password
system.sms.valid_password=Please enter a valid password.
system.sms.systemType=System Type (Optional)
system.sms.valid_systemType=Please enter a valid system type.
system.sms.save=Save Changes
system.sms.send_test=Send Test SMS...
system.smstest.title=SMS Settings
system.smstest.success=SMS was successfully sent. Verify it was sent by checking the SMS inbox of the recipient.
system.smstest.failure=An error occurred while trying to send the SMS message. The error message: <i>{0}</i>.
system.smstest.info=Use the form below to send a test message. Note that SMS does not guarantee speedy delivery, but \
generally, your message should arrive within moments.
system.smstest.invalid-service-config=The SMS service has not been configured properly. Please go back to the {0}SMS \
settings page{1} and address all issues presented there.
system.smstest.recipient=Recipient
system.smstest.valid_recipient=Please enter a recipient (phone number)
system.smstest.message=Message
system.smstest.valid_message=Please provide a short message.
system.smstest.send=Send
system.smstest.cancel=Cancel/Go Back
# File Transfer Proxy
filetransferproxy.settings.title=File Transfer Proxy Settings
......
package org.jivesoftware.util;
import org.jsmpp.InvalidResponseException;
import org.jsmpp.PDUException;
import org.jsmpp.bean.*;
import org.jsmpp.extra.NegativeResponseException;
import org.jsmpp.extra.ResponseTimeoutException;
import org.jsmpp.session.BindParameter;
import org.jsmpp.session.SMPPSession;
import org.jsmpp.util.AbsoluteTimeFormatter;
import org.jsmpp.util.TimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* A service to send SMS messages.<p>
*
* This class is configured with a set of Jive properties. Note that each service provider can require a different set
* of properties to be set.
* <ul>
* <li><tt>sms.smpp.host</tt> -- the host name of your SMPP Server or SMSC, i.e. smsc.example.org. The default value is "localhost".
* <li><tt>sms.smpp.port</tt> -- the port on which the SMSC is listening. Defaults to 2775.
* <li><tt>sms.smpp.systemId</tt> -- the 'user name' to use when connecting to the SMSC.
* <li><tt>sms.smpp.password</tt> -- the password that authenticates the systemId value when connecting to the SMSC.
* <li><tt>sms.smpp.systemType</tt> -- an optional system type, which, if defined, will be used when connecting to the SMSC.
* <li><tt>sms.smpp.receive.ton</tt> -- The type-of-number value for 'receiving' SMS messages. Defaults to 'UNKNOWN'.
* <li><tt>sms.smpp.receive.npi</tt> -- The number-plan-indicator value for 'receiving' SMS messages. Defaults to 'UNKNOWN'.
* <li><tt>sms.smpp.source.ton</tt> -- The type-of-number value for the source of SMS messages. Defaults to 'UNKNOWN'.
* <li><tt>sms.smpp.source.npi</tt> -- The number-plan-indicator value for the source of SMS messages. Defaults to 'UNKNOWN'.
* <li><tt>sms.smpp.source.address</tt> -- The source address of SMS messages.
* <li><tt>sms.smpp.destination.ton</tt> -- The type-of-number value for the destination of SMS messages. Defaults to 'UNKNOWN'.
* <li><tt>sms.smpp.destination.npi</tt> -- The number-plan-indicator value for the destination of SMS messages. Defaults to 'UNKNOWN'.
* </ul>
*
* @author Guus der Kinderen, guus@goodbytes.nl
*/
public class SmsService
{
private static final Logger Log = LoggerFactory.getLogger( SmsService.class );
private static TimeFormatter timeFormatter = new AbsoluteTimeFormatter();
private static SmsService INSTANCE;
public static synchronized SmsService getInstance()
{
if ( INSTANCE == null )
{
INSTANCE = new SmsService();
}
return INSTANCE;
}
/**
* Causes a new SMS message to be sent.
*
* Note that the message is sent asynchronously. This method does not block. A successful invocation does not
* guarantee successful delivery
*
* @param message The body of the message (cannot be null or empty).
* @param recipient The address / phone number to which the message is to be send (cannot be null or empty).
*/
public void send( String message, String recipient )
{
if ( message == null || message.isEmpty() ) {
throw new IllegalArgumentException( "Argument 'message' cannot be null or an empty String." );
}
if ( recipient == null || recipient.isEmpty() ) {
throw new IllegalArgumentException( "Argument 'recipient' cannot be null or an empty String." );
}
TaskEngine.getInstance().submit(new SmsTask( message, recipient ) );
}
/**
* Causes a new SMS message to be sent.
*
* This method differs from {@link #send(String, String)} in that the message is sent before this method returns,
* rather than queueing the messages to be sent later (in an async fashion). As a result, any exceptions that occur
* while sending the message are thrown by this method (which can be useful to test the configuration of this
* service).
*
* @param message The body of the message (cannot be null or empty).
* @param recipient The address / phone number to which the message is to be send (cannot be null or empty).
* @throws PDUException
* @throws ResponseTimeoutException
* @throws InvalidResponseException
* @throws NegativeResponseException
* @throws IOException
*/
public void sendImmediately( String message, String recipient ) throws PDUException, ResponseTimeoutException, InvalidResponseException, NegativeResponseException, IOException
{
if ( message == null || message.isEmpty() ) {
throw new IllegalArgumentException( "Argument 'message' cannot be null or an empty String." );
}
if ( recipient == null || recipient.isEmpty() ) {
throw new IllegalArgumentException( "Argument 'recipient' cannot be null or an empty String." );
}
try
{
new SmsTask( message, recipient ).sendMessage();
}
catch ( PDUException | ResponseTimeoutException | InvalidResponseException | NegativeResponseException | IOException e )
{
Log.error( "An exception occurred while sending a SMS message (to '{}')", recipient, e);
throw e;
}
}
/**
* Checks if an exception in the chain of the provided throwable contains a 'command status' that can be
* translated in a somewhat more helpful error message.
*
* The list of error messages was taken from http://www.smssolutions.net/tutorials/smpp/smpperrorcodes/
* @param ex The exception in which to search for a command status.
* @return
*/
public static String getDescriptiveMessage( Throwable ex )
{
if ( ex instanceof NegativeResponseException )
{
final Map<Integer, String> errors = new HashMap<>();
errors.put( 0x00000000, "No Error" );
errors.put( 0x00000001, "Message too long" );
errors.put( 0x00000002, "Command length is invalid" );
errors.put( 0x00000003, "Command ID is invalid or not supported" );
errors.put( 0x00000004, "Incorrect bind status for given command" );
errors.put( 0x00000005, "Already bound" );
errors.put( 0x00000006, "Invalid Priority Flag" );
errors.put( 0x00000007, "Invalid registered delivery flag" );
errors.put( 0x00000008, "System error" );
errors.put( 0x0000000A, "Invalid source address" );
errors.put( 0x0000000B, "Invalid destination address" );
errors.put( 0x0000000C, "Message ID is invalid" );
errors.put( 0x0000000D, "Bind failed" );
errors.put( 0x0000000E, "Invalid password" );
errors.put( 0x0000000F, "Invalid System ID" );
errors.put( 0x00000011, "Cancelling message failed" );
errors.put( 0x00000013, "Message recplacement failed" );
errors.put( 0x00000014, "Message queue full" );
errors.put( 0x00000015, "Invalid service type" );
errors.put( 0x00000033, "Invalid number of destinations" );
errors.put( 0x00000034, "Invalid distribution list name" );
errors.put( 0x00000040, "Invalid destination flag" );
errors.put( 0x00000042, "Invalid submit with replace request" );
errors.put( 0x00000043, "Invalid esm class set" );
errors.put( 0x00000044, "Invalid submit to ditribution list" );
errors.put( 0x00000045, "Submitting message has failed" );
errors.put( 0x00000048, "Invalid source address type of number ( TON )" );
errors.put( 0x00000049, "Invalid source address numbering plan ( NPI )" );
errors.put( 0x00000050, "Invalid destination address type of number ( TON )" );
errors.put( 0x00000051, "Invalid destination address numbering plan ( NPI )" );
errors.put( 0x00000053, "Invalid system type" );
errors.put( 0x00000054, "Invalid replace_if_present flag" );
errors.put( 0x00000055, "Invalid number of messages" );
errors.put( 0x00000058, "Throttling error" );
errors.put( 0x00000061, "Invalid scheduled delivery time" );
errors.put( 0x00000062, "Invalid Validty Period value" );
errors.put( 0x00000063, "Predefined message not found" );
errors.put( 0x00000064, "ESME Receiver temporary error" );
errors.put( 0x00000065, "ESME Receiver permanent error" );
errors.put( 0x00000066, "ESME Receiver reject message error" );
errors.put( 0x00000067, "Message query request failed" );
errors.put( 0x000000C0, "Error in the optional part of the PDU body" );
errors.put( 0x000000C1, "TLV not allowed" );
errors.put( 0x000000C2, "Invalid parameter length" );
errors.put( 0x000000C3, "Expected TLV missing" );
errors.put( 0x000000C4, "Invalid TLV value" );
errors.put( 0x000000FE, "Transaction delivery failure" );
errors.put( 0x000000FF, "Unknown error" );
errors.put( 0x00000100, "ESME not authorised to use specified servicetype" );
errors.put( 0x00000101, "ESME prohibited from using specified operation" );
errors.put( 0x00000102, "Specified servicetype is unavailable" );
errors.put( 0x00000103, "Specified servicetype is denied" );
errors.put( 0x00000104, "Invalid data coding scheme" );
errors.put( 0x00000105, "Invalid source address subunit" );
errors.put( 0x00000106, "Invalid destination address subunit" );
errors.put( 0x0000040B, "Insufficient credits to send message" );
errors.put( 0x0000040C, "Destination address blocked by the ActiveXperts SMPP Demo Server" );
String error = errors.get( ( (NegativeResponseException) ex ).getCommandStatus() );
if ( ex.getMessage() != null && !ex.getMessage().isEmpty() )
{
error += " (exception message: '" + ex.getMessage() + "')";
}
return error;
}
else if ( ex.getCause() != null )
{
return getDescriptiveMessage( ex.getCause() );
}
return ex.getMessage();
}
/**
* Runnable that allows an SMS to be sent in a different thread.
*/
private static class SmsTask implements Runnable
{
// SMSC connection settings
private final String host = JiveGlobals.getProperty( "sms.smpp.host", "localhost" );
private final int port = JiveGlobals.getIntProperty( "sms.smpp.port", 2775 );
private final String systemId = JiveGlobals.getProperty( "sms.smpp.systemId" );
private final String password = JiveGlobals.getProperty( "sms.smpp.password" );
private final String systemType = JiveGlobals.getProperty( "sms.smpp.systemType" );
// Settings that apply to 'receiving' SMS. Should not apply to this implementation, as we're not receiving anything..
private final TypeOfNumber receiveTon = JiveGlobals.getEnumProperty( "sms.smpp.receive.ton", TypeOfNumber.class, TypeOfNumber.UNKNOWN );
private final NumberingPlanIndicator receiveNpi = JiveGlobals.getEnumProperty( "sms.smpp.receive.npi", NumberingPlanIndicator.class, NumberingPlanIndicator.UNKNOWN );
// Settings that apply to source of an SMS message.
private final TypeOfNumber sourceTon = JiveGlobals.getEnumProperty( "sms.smpp.source.ton", TypeOfNumber.class, TypeOfNumber.UNKNOWN );
private final NumberingPlanIndicator sourceNpi = JiveGlobals.getEnumProperty( "sms.smpp.source.npi", NumberingPlanIndicator.class, NumberingPlanIndicator.UNKNOWN );
private final String sourceAddress = JiveGlobals.getProperty( "sms.smpp.source.address" );
// Settings that apply to destination of an SMS message.
private final TypeOfNumber destinationTon = JiveGlobals.getEnumProperty( "sms.smpp.destination.ton", TypeOfNumber.class, TypeOfNumber.UNKNOWN );
private final NumberingPlanIndicator destinationNpi = JiveGlobals.getEnumProperty( "sms.smpp.destination.npi", NumberingPlanIndicator.class, NumberingPlanIndicator.UNKNOWN );
private final String destinationAddress;
private final byte[] message;
// Non-configurable defaults (for now - TODO?)
private final ESMClass esm = new ESMClass();
private final byte protocolId = 0;
private final byte priorityFlag = 1;
private final String serviceType = "CMT";
private final String scheduleDeliveryTime = timeFormatter.format( new Date() );
private final String validityPeriod = null;
private final RegisteredDelivery registeredDelivery = new RegisteredDelivery( SMSCDeliveryReceipt.DEFAULT );
private final byte replaceIfPresentFlag = 0;
private final DataCoding dataCoding = new GeneralDataCoding( Alphabet.ALPHA_DEFAULT, MessageClass.CLASS1, false );
private final byte smDefaultMsgId = 0;
SmsTask( String message, String destinationAddress )
{
this.message = message.getBytes();
this.destinationAddress = destinationAddress;
}
@Override
public void run()
{
try
{
sendMessage();
}
catch ( PDUException | ResponseTimeoutException | InvalidResponseException | NegativeResponseException | IOException e )
{
Log.error( "An exception occurred while sending a SMS message (to '{}')", destinationAddress, e);
}
}
public void sendMessage() throws IOException, PDUException, InvalidResponseException, NegativeResponseException, ResponseTimeoutException
{
final SMPPSession session = new SMPPSession();
try
{
session.connectAndBind( host, port, new BindParameter( BindType.BIND_TX, systemId, password, systemType, receiveTon, receiveNpi, null ) );
final String messageId = session.submitShortMessage(
serviceType,
sourceTon, sourceNpi, sourceAddress,
destinationTon, destinationNpi, destinationAddress,
esm, protocolId, priorityFlag,
scheduleDeliveryTime, validityPeriod, registeredDelivery, replaceIfPresentFlag,
dataCoding, smDefaultMsgId, message );
Log.debug( "Message submitted, message_id is '{}'.", messageId );
}
finally
{
session.unbindAndClose();
}
}
}
}
......@@ -53,6 +53,11 @@
url="system-email.jsp"
description="${sidebar.server-email.descr}"/>
<!-- SMS -->
<item id="system-sms" name="${sidebar.server-sms}"
url="system-sms.jsp"
description="${sidebar.server-sms.descr}"/>
<!-- Security Audit Viewer -->
<item id="security-audit-viewer" name="${sidebar.security-audit-viewer}"
url="security-audit-viewer.jsp"
......
<%@ page import="java.util.*,
org.jivesoftware.util.*"
errorPage="error.jsp"
%>
<%@ taglib uri="admin" prefix="admin" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %>
<%
// get parameters
String host = ParamUtils.getParameter(request,"host");
int port = ParamUtils.getIntParameter(request,"port",0);
String systemId = ParamUtils.getParameter(request,"systemId");
String password = ParamUtils.getParameter(request,"password");
String systemType = ParamUtils.getParameter(request,"systemType");
boolean save = request.getParameter("save") != null;
boolean test = request.getParameter("test") != null;
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
final Map<String,String> errors = new HashMap<String,String>();
if (save) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
errors.put("csrf", "CSRF Failure!");
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a test request
if (test) {
response.sendRedirect("system-smstest.jsp");
return;
}
if ( !save )
{
// Not trying to save new values? Use the existing values.
host = JiveGlobals.getProperty( "sms.smpp.host", "localhost" );
port = JiveGlobals.getIntProperty( "sms.smpp.port", 2775 );
systemId = JiveGlobals.getProperty( "sms.smpp.systemId" );
password = JiveGlobals.getProperty( "sms.smpp.password" );
systemType = JiveGlobals.getProperty( "sms.smpp.systemType" );
}
if ( host == null || host.isEmpty() )
{
errors.put( "host", "cannot be missing or empty." );
}
if ( port < 0 || port > 65535 )
{
errors.put( "port", "must be a number between 0 and 65535." );
}
if ( systemId == null || systemId.isEmpty() )
{
errors.put( "systemId", "cannot be missing or empty." );
}
if ( password == null || password.isEmpty() )
{
errors.put( "password", "cannot be missing or empty." );
}
if (errors.isEmpty() && save)
{
JiveGlobals.setProperty( "sms.smpp.host", host );
JiveGlobals.setProperty( "sms.smpp.port", Integer.toString(port) );
JiveGlobals.setProperty( "sms.smpp.systemId", systemId );
JiveGlobals.setProperty( "sms.smpp.password", password );
JiveGlobals.setProperty( "sms.smpp.systemType", systemType );
// Log the event
webManager.logEvent("updated sms service settings", "host = "+host+"\nport = "+port+"\nusername = "+ systemId +"\nsystemType = "+systemType);
JiveGlobals.setProperty("sms.configured", "true");
response.sendRedirect("system-sms.jsp?success=true");
}
pageContext.setAttribute( "errors", errors );
pageContext.setAttribute( "host", host );
pageContext.setAttribute( "port", port);
pageContext.setAttribute( "systemId", systemId );
pageContext.setAttribute( "password", password );
pageContext.setAttribute( "systemType", systemType );
%>
<html>
<head>
<title><fmt:message key="system.sms.title"/></title>
<meta name="pageID" content="system-sms"/>
</head>
<body>
<c:if test="${not empty errors}">
<admin:infobox type="error">
<fmt:message key="system.sms.config_failure" />
</admin:infobox>
</c:if>
<c:if test="${empty errors and param.success}">
<admin:infobox type="success"><fmt:message key="system.sms.update_success" /></admin:infobox>
</c:if>
<p>
<fmt:message key="system.sms.info" />
</p>
<form action="system-sms.jsp" method="post">
<fmt:message key="system.sms.name" var="plaintextboxtitle"/>
<admin:contentBox title="${plaintextboxtitle}">
<table width="80%" cellpadding="3" cellspacing="0" border="0">
<tr>
<td width="30%" nowrap>
<fmt:message key="system.sms.host" />:
</td>
<td nowrap>
<input type="text" name="host" value="${fn:escapeXml(host)}" size="40" maxlength="150">
</td>
</tr>
<c:if test="${ not empty errors['host']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.sms.valid_host" />
</td>
</tr>
</c:if>
<tr>
<td nowrap>
<fmt:message key="system.sms.port" />:
</td>
<td nowrap>
<input type="text" name="port" value="${fn:escapeXml(port)}" size="10" maxlength="15">
</td>
</tr>
<c:if test="${ not empty errors['port']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.sms.valid_port" />
</td>
</tr>
</c:if>
<!-- spacer -->
<tr><td colspan="2">&nbsp;</td></tr>
<tr>
<td width="30%" nowrap>
<fmt:message key="system.sms.systemId" />:
</td>
<td nowrap>
<input type="text" name="systemId" value="${fn:escapeXml(systemId)}" size="40" maxlength="150">
</td>
</tr>
<c:if test="${ not empty errors['systemId']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.sms.valid_systemId" />
</td>
</tr>
</c:if>
<tr>
<td width="30%" nowrap>
<fmt:message key="system.sms.password" />:
</td>
<td nowrap>
<input type="password" name="password" value="${fn:escapeXml(password)}" size="40" maxlength="8">
</td>
</tr>
<c:if test="${ not empty errors['password']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.sms.valid_password" />
</td>
</tr>
</c:if>
<!-- spacer -->
<tr><td colspan="2">&nbsp;</td></tr>
<tr>
<td width="30%" nowrap>
<fmt:message key="system.sms.systemType" />:
</td>
<td nowrap>
<input type="text" name="systemType" value="${fn:escapeXml(systemType)}" size="40" maxlength="150">
</td>
</tr>
<c:if test="${ not empty errors['systemType']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.sms.valid_systemType" />
</td>
</tr>
</c:if>
</table>
</admin:contentBox>
<input type="hidden" name="csrf" value="${csrf}"/>
<input type="submit" name="save" value="<fmt:message key="system.sms.save" />">
<input type="submit" name="test" value="<fmt:message key="system.sms.send_test" />" ${ not empty errors ? 'disabled' : ''}>
</form>
</body>
</html>
<%--
- Copyright (C) 2005-2008 Jive Software. All rights reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--%>
<%@ page import="org.jivesoftware.util.*,
java.util.*"
errorPage="error.jsp"
%>
<%@ taglib uri="admin" prefix="admin" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%-- Define Administration Bean --%>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %>
<% // Get paramters
boolean doTest = request.getParameter("test") != null;
boolean cancel = request.getParameter("cancel") != null;
String recipient = ParamUtils.getParameter(request, "recipient");
String message = ParamUtils.getParameter(request, "message");
// Cancel if requested
if (cancel) {
response.sendRedirect("system-sms.jsp");
return;
}
// Validate input
Map<String, String> errors = new HashMap<String, String>();
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (doTest) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
doTest = false;
errors.put("csrf", "CSRF Failure!");
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// See if the service has basic configuration.
if ( JiveGlobals.getProperty( "sms.smpp.host" ) == null ) {
errors.put( "host", "cannot be missing or empty." );
}
if ( JiveGlobals.getProperty( "sms.smpp.systemId" ) == null )
{
errors.put( "systemId", "cannot be missing or empty." );
}
if (JiveGlobals.getProperty( "sms.smpp.password" ) == null )
{
errors.put( "password", "cannot be missing or empty.");
}
if (doTest) {
if (recipient == null || recipient.trim().isEmpty() ) {
errors.put("recipient", "Recipient cannot be missing or empty.");
}
if (message == null || message.trim().isEmpty() ) {
errors.put("message", "Message cannot be missing or empty.");
}
if (errors.isEmpty())
{
final SmsService service = SmsService.getInstance();
try
{
service.sendImmediately( message, recipient );
response.sendRedirect("system-smstest.jsp?sent=true&success=true");
return;
}
catch ( Exception e )
{
errors.put( "sendfailed", SmsService.getDescriptiveMessage( e ) );
}
}
}
pageContext.setAttribute( "errors", errors );
pageContext.setAttribute( "recipient", recipient );
pageContext.setAttribute( "message", message );
%>
<html>
<head>
<title><fmt:message key="system.smstest.title"/></title>
<meta name="pageID" content="system-sms"/>
</head>
<body>
<c:if test="${not empty errors}">
<admin:infobox type="error">
<c:choose>
<c:when test="${ not empty errors['host'] or not empty errors['systemId'] or not empty errors['password']}">
<fmt:message key="system.smstest.invalid-service-config">
<fmt:param value="<a href=\"system-sms.jsp\">"/>
<fmt:param value="</a>"/>
</fmt:message>
</c:when>
<c:when test="${ not empty errors['sendfailed']}">
<fmt:message key="system.smstest.failure">
<fmt:param value="${errors['sendfailed']}"/>
</fmt:message>
</c:when>
<c:otherwise>
<fmt:message key="system.sms.config_failure" />
</c:otherwise>
</c:choose>
</admin:infobox>
</c:if>
<c:if test="${empty errors and param.success}">
<admin:infobox type="success"><fmt:message key="system.smstest.success" /></admin:infobox>
</c:if>
<p>
<fmt:message key="system.smstest.info" />
</p>
<form action="system-smstest.jsp" method="post">
<table cellpadding="3" cellspacing="0" border="0">
<tbody>
<tr>
<td>
<fmt:message key="system.smstest.recipient" />:
</td>
<td>
<input type="text" name="recipient" value="${fn:escapeXml(recipient)}"size="40" maxlength="100">
</td>
</tr>
<c:if test="${ not empty errors['recipient']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.smstest.valid_recipient" />
</td>
</tr>
</c:if>
<tr valign="top">
<td>
<fmt:message key="system.smstest.message" />:
</td>
<td>
<textarea name="message" cols="45" rows="5" maxlength="140" wrap="virtual"><c:out value="${message}"/></textarea>
</td>
</tr>
<c:if test="${ not empty errors['message']}">
<tr>
<td nowrap>
&nbsp;
</td>
<td nowrap class="jive-error-text">
<fmt:message key="system.smstest.valid_message" />
</td>
</tr>
</c:if>
<tr>
<td colspan="2">
<br>
<input type="hidden" name="csrf" value="${csrf}">
<input type="submit" name="test" value="<fmt:message key="system.smstest.send" />" ${ not empty errors['host'] or not empty errors['systemId'] or not empty errors['password'] ? 'disabled' : ''}>
<input type="submit" name="cancel" value="<fmt:message key="system.smstest.cancel" />">
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment