📄 cservice.java
字号:
// SMSLib for Java
// An open-source API Library for sending and receiving SMS via a GSM modem.
// Copyright (C) 2002-2006, Thanasis Delenikas, Athens/GREECE
// Web Site: http://www.smslib.org
//
// SMSLib is distributed under the LGPL license.
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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
package org.smslib;
import java.io.*;
import java.util.*;
import org.apache.log4j.*;
/**
* This is the main SMSLib service class.
*/
public class CService
{
/**
* Dummy synchronization object.
*/
public static Object _SYNC_;
/**
* Product name.
*/
public static final String _name = "SMSLib for Java";
/**
* Product version.
*/
public static final String _version = "v2.0.0 (B1)";
/**
* Receive modes.
* <p>
* Sync: Synchronous Reading.<br />
* AsyncCnmi: Asynchronous, based on CNMI indications.<br />
* AsyncPoll: Asynchronous, based on polling.
*
* @see #setReceiveMode(ReceiveMode)
* @see #getReceiveMode()
*/
public static enum ReceiveMode { Sync, AsyncCnmi, AsyncPoll }
private static final String LOG_CONF = "smslib-log.conf";
private int keepAliveInterval = 30 * 1000;
private int asyncPollInterval = 10 * 1000;
private CIncomingMessage.MessageClass asyncRecvClass = CIncomingMessage.MessageClass.All;
private int retriesNoResponse = 4;
private int delayNoResponse = 2000;
private int retriesCmsErrors = 4;
private int delayCmsErrors = 2000;
private Logger log;
private static final String VALUE_NOT_REPORTED = "* N/A *";
private String smscNumber;
private String simPin;
private ReceiveMode receiveMode;
private AbstractATHandler atHandler;
private CNewMsgMonitor newMsgMonitor;
private CSerialDriver serialDriver;
private boolean connected;
private CDeviceInfo deviceInfo;
private CKeepAliveThread keepAliveThread;
private CReceiveThread receiveThread;
private ISmsMessageListener messageHandler;
private int outMpRefNo;
/**
* CService constructor.
*
* @param port The comm port to use (i.e. COM1, /dev/ttyS1 etc).
* @param baud The baud rate. 57600 is a good number to start with.
* @param gsmDeviceManufacturer The manufacturer of the modem (i.e. Wavecom, Nokia, Siemens, etc).
* @param gsmDeviceModel The model (i.e. M1306B, 6310i, etc).
*/
public CService(String port, int baud, String gsmDeviceManufacturer, String gsmDeviceModel)
{
_SYNC_ = new Object();
log = Logger.getLogger("org.smslib");
if (new File(LOG_CONF).exists()) PropertyConfigurator.configure(LOG_CONF);
else
{
BasicConfigurator.configure();
log.setLevel(Level.WARN);
log.setLevel(Level.DEBUG);
}
smscNumber = "";
simPin = null;
connected = false;
serialDriver = new CSerialDriver(port, baud, log);
deviceInfo = new CDeviceInfo();
newMsgMonitor = new CNewMsgMonitor();
log.info(_name + " / " + _version);
log.info("Using port: " + port + " @ " + baud + " baud.");
log.info("JRE Version: " + System.getProperty("java.version"));
log.info("JRE Impl Version: " + System.getProperty("java.vm.version"));
log.info("O/S: " + System.getProperty("os.name") + " / " + System.getProperty("os.arch") + " / " + System.getProperty("os.version"));
try
{
atHandler = AbstractATHandler.load(serialDriver, log, this, gsmDeviceManufacturer, gsmDeviceModel);
log.info("Using " + atHandler.getDescription() + " AT handler.");
}
catch (Exception ex)
{
log.fatal("CANNOT INITIALIZE HANDLER (" + ex.getMessage() + ")");
}
receiveMode = ReceiveMode.Sync;
receiveThread = null;
outMpRefNo = new Random().nextInt();
if (outMpRefNo < 0) outMpRefNo *= -1;
outMpRefNo %= 65536;
}
/**
* Return the status of the connection.<p>
* <strong>Warning</strong>: The method return the "theoretical" status of the connection, without testing the actual connection at the time of the call.
*
* @return True if the GSM device is connected.
* @see #connect()
* @see #disconnect()
*/
public boolean getConnected() { return connected; }
/**
* Returns the DeviceInfo class.
*
* @see CDeviceInfo
*/
public CDeviceInfo getDeviceInfo() { return deviceInfo; }
/**
* Sets the SMSC number. Needed in rare cases - normally, you should <strong>not</strong> set the SMSC number yourself and let the GSM device get it from its SIM.
*
* @param smscNumber The SMSC number (international format).
* @see #getSmscNumber()
*/
public void setSmscNumber(String smscNumber) { this.smscNumber = smscNumber; }
/**
* Returns the SMSC number previously set with setSmscNumber() call.
*
* @return The SMSC number.
* @see #setSmscNumber(String)
*/
public String getSmscNumber() { return smscNumber; }
/**
* Sets the SIM Pin.
*
* @param simPin The SIM pin code.
* @see #getSimPin()
*/
public void setSimPin(String simPin) { this.simPin = simPin; }
/**
* Returns the SIM Pin previously set with setSimPin().
*
* @return The SIM Pin code.
* @see #setSimPin(String)
*/
public String getSimPin() { return simPin; }
public void setMessageHandler(ISmsMessageListener messageHandler) { this.messageHandler = messageHandler; }
protected ISmsMessageListener getMessageHandler() { return messageHandler; }
/**
* Sets the Async Poll Interval, in seconds, i.e. every how many seconds will SMSLib
* poll the GSM modem for new messages.
*
* @param secs The interval in seconds.
* @see #getAsyncPollInterval()
* @see #setAsyncRecvClass(CIncomingMessage.MessageClass)
* @see #getAsyncRecvClass()
*/
public void setAsyncPollInterval(int secs) { this.asyncPollInterval = secs * 1000; }
/**
* Returns the Async Poll Interval, in seconds.
*
* @return The Poll Interval in seconds.
* @see #setAsyncPollInterval(int)
* @see #setAsyncRecvClass(CIncomingMessage.MessageClass)
* @see #getAsyncRecvClass()
*/
public int getAsyncPollInterval() { return (asyncPollInterval / 1000); }
public void setAsyncRecvClass(CIncomingMessage.MessageClass msgClass) { asyncRecvClass = msgClass; }
public CIncomingMessage.MessageClass getAsyncRecvClass() { return asyncRecvClass; }
/**
* Sets the Keep-Alive Interval, i.e. every how many seconds the Keep-Alive thread will run
* and send a dummy OK command to the GSM modem. This is used to keep the serial port
* alive and prevent it from timing out. The interval is, by default, set to 30 seconds which
* should be enough for all modems.
*
* @param secs The Keep-Alive Interval in seconds.
* @see #getKeepAliveInterval()
*/
public void setKeepAliveInterval(int secs) { this.keepAliveInterval = secs * 1000; }
/**
* Returns the Keep-Alive Interval, in seconds.
*
* @return The Keep-Alive Interval in seconds.
* @see #setKeepAliveInterval(int)
*/
public int getKeepAliveInterval() { return keepAliveInterval / 1000; }
public void setRetriesNoResponse(int retries) { this.retriesNoResponse = retries; }
public int getRetriesNoResponse() { return retriesNoResponse; }
public void setDelayNoResponse(int delay) { this.delayNoResponse = delay * 1000; }
public int getDelayNoResponse() { return delayNoResponse; }
public void setRetriesCmsErrors(int retries) { this.retriesCmsErrors = retries; }
public int getRetriesCmsErrors() { return retriesCmsErrors; }
public void setDelayCmsErrors(int delay) { this.delayCmsErrors = delay * 1000; }
public int getDelayCmsErrors() { return delayCmsErrors; }
/**
* Returns the Log4J logger object used by SMSLib.
*
* @return The Log4J logger object.
*/
public Logger getLogger() { return log; }
/**
* Sets the receive mode.
*
* @param receiveMode The Receive Mode.
*/
public void setReceiveMode(ReceiveMode receiveMode) throws Exception
{
this.receiveMode = receiveMode;
if (connected)
{
if (receiveMode == ReceiveMode.AsyncCnmi)
{
if (!atHandler.enableIndications()) log.warn("Could not enable CMTI indications, continuing without them...");
}
else
{
if (!atHandler.disableIndications()) log.warn("Could not disable CMTI indications, continuing without them...");
}
}
}
/**
* Returns the Receive Mode.
*
* @return The Receive Mode.
*/
public ReceiveMode getReceiveMode() { return receiveMode; }
/**
* Connects to the GSM modem.<p>
* The connect() function should be called before any operations. Its purpose is to open the serial link, check for modem existence, initialize modem, start background threads and prepare for subsequent operations.
*
* @see #disconnect()
* @throws NotConnectedException No compatible modem (or no modem at all) found.
* @throws AlreadyConnectedException If already connected.
* @throws NoPinException If PIN is requested from the modem but no PIN is defined.
* @throws InvalidPinException If the defined PIN is not accepted by the modem.
* @throws NoPduSupportException The modem does not support PDU mode - fatal error!
*/
public void connect() throws Exception
{
synchronized (_SYNC_)
{
if (getConnected()) throw new AlreadyConnectedException();
else try
{
serialDriver.open();
atHandler.sync();
serialDriver.emptyBuffer();
atHandler.reset();
serialDriver.setNewMsgMonitor(newMsgMonitor);
if (atHandler.isAlive())
{
if (atHandler.waitingForPin())
{
if (getSimPin() == null) throw new NoPinException();
else if (!atHandler.enterPin(getSimPin())) throw new InvalidPinException();
}
atHandler.init();
atHandler.echoOff();
waitForNetworkRegistration();
atHandler.setVerboseErrors();
if (!atHandler.setPduMode()) throw new NoPduSupportException();
connected = true;
setReceiveMode(receiveMode);
refreshDeviceInfo();
receiveThread = new CReceiveThread();
receiveThread.start();
keepAliveThread = new CKeepAliveThread();
keepAliveThread.start();
}
else throw new NotConnectedException("GSM device is not responding.");
}
catch (Exception e)
{
disconnect();
throw e;
}
}
}
/**
* Disconnects from the GSM modem.<p>
* This should be the last function called. Closes serial connection, shuts down background threads and performs clean-up.<p>
* <strong>Notes</strong>
* <ul>
* <li>Do not connect and disconnect continously - at least if you can avoid it. It takes time and resources. Connect once and stay connected.</li>
* </ul>
*
* @see #connect()
*/
public void disconnect()
{
serialDriver.killMe();
if (receiveThread != null)
{
receiveThread.killMe();
receiveThread.interrupt();
while (!receiveThread.killed()) try { receiveThread.join(); } catch (Exception e) {}
receiveThread = null;
}
if (keepAliveThread != null)
{
keepAliveThread.killMe();
keepAliveThread.interrupt();
while (!keepAliveThread.killed()) try { keepAliveThread.join(); } catch (Exception e) {}
keepAliveThread = null;
}
try { serialDriver.close(); } catch (Exception e) {}
connected = false;
}
/**
* Reads SMS messages from the GSM modem.<p>
* This method fills the supplied list with all messages of the specified message class.
*
* @param messageList The list to be populated with messages.
* @param messageClass The message class of the messages to read
* @throws NotConnectedException Either connect() is not called or modem has been disconnected.
* @see CIncomingMessage
* @see CIncomingMessage.MessageClass
* @see #sendMessage(COutgoingMessage)
*/
public void readMessages(List<CIncomingMessage> messageList, CIncomingMessage.MessageClass messageClass) throws Exception
{
int i, j, memIndex;
String response, line, pdu;
BufferedReader reader;
CIncomingMessage mpMsg = null;
String memLoc;
synchronized (_SYNC_)
{
if (getConnected())
{
atHandler.switchToCmdMode();
memLoc = atHandler.getMemoryLocations();
for (int ml = 0; ml < (memLoc.length() / 2); ml++)
{
if (atHandler.setMemoryLocation(memLoc.substring((ml * 2), (ml * 2) + 2)))
{
response = atHandler.listMessages(messageClass);
response = response.replaceAll("\\s+OK\\s+", "\nOK");
reader = new BufferedReader(new StringReader(response));
for (;;)
{
line = reader.readLine();
if (line == null) break;
line = line.trim();
if (line.length() > 0) break;
}
while (true)
{
if (line == null) break;
line = line.trim();
if (line.length() <= 0 || line.equalsIgnoreCase("OK")) break;
i = line.indexOf(':');
j = line.indexOf(',');
memIndex = Integer.parseInt(line.substring(i + 1, j).trim());
pdu = reader.readLine();
try
{
if (isIncomingMessage(pdu))
{
CIncomingMessage msg;
msg = new CIncomingMessage(pdu, memIndex, memLoc.substring((ml * 2), (ml * 2) + 2));
if (msg.getMpRefNo() == 0)
{
messageList.add(msg);
deviceInfo.getStatistics().incTotalIn();
}
else
{
if (msg.getMpSeqNo() == 1)
{
if (mpMsg == null)
{
mpMsg = new CIncomingMessage(pdu, memIndex, memLoc.substring((ml * 2), (ml * 2) + 2));
mpMsg.setMpMemIndex(memIndex);
}
}
else if ((msg.getMpRefNo() == mpMsg.getMpRefNo()) && (msg.getMpSeqNo() == mpMsg.getMpSeqNo() + 1))
{
mpMsg.addText(msg.getText());
mpMsg.setMpSeqNo(msg.getMpSeqNo());
mpMsg.setMpMemIndex(memIndex);
if (mpMsg.getMpSeqNo() == mpMsg.getMpMaxNo())
{
mpMsg.setMemIndex(-1);
messageList.add(mpMsg);
mpMsg = null;
}
}
}
}
else if (isStatusReportMessage(pdu))
{
messageList.add(new CStatusReportMessage(pdu, memIndex, memLoc.substring((ml * 2), (ml * 2) + 2)));
deviceInfo.getStatistics().incTotalIn();
}
}
catch (Exception e)
{
log.error("Unhandled SMS in inbox, skipping...");
}
line = reader.readLine();
}
reader.close();
}
}
}
else throw new NotConnectedException();
}
}
/**
* Sends an SMS message from the GSM modem.<p>
* This method actually wraps the message in a list and calls #sendMessage(List) that does the job.
*
* @param message The message to be sent.
* @throws NotConnectedException Either connect() is not called or modem has been disconnected.
* @see #sendMessage(List)
* @see #readMessages(List, CIncomingMessage.MessageClass)
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -