0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package com.sun.midp.io.j2me.sms;
0028:
0029: import com.sun.midp.io.j2me.ProtocolBase;
0030:
0031: import com.sun.midp.io.HttpUrl;
0032: import com.sun.midp.security.Permissions;
0033: import java.io.DataInputStream;
0034: import java.io.DataOutputStream;
0035: import java.io.InputStream;
0036: import java.io.OutputStream;
0037: import java.util.Vector;
0038: import javax.microedition.io.Connector;
0039: import javax.microedition.io.Connection;
0040: import javax.wireless.messaging.Message;
0041: import javax.wireless.messaging.MessageConnection;
0042:
0043: // Exceptions
0044: import java.io.IOException;
0045: import java.io.InterruptedIOException;
0046:
0047: /**
0048: * SMS message connection implementation.
0049: *
0050: * <code>Protocol</code> itself is not instantiated. Instead, the application
0051: * calls <code>Connector.open</code> with an SMS URL string and obtains a
0052: * {@link javax.wireless.messaging.MessageConnection MessageConnection}
0053: * object. It is an instance of <code>MessageConnection</code>
0054: * that is instantiated. The Generic Connection Framework mechanism
0055: * in CLDC will return a <code>Protocol</code> object, which is the
0056: * implementation of <code>MessageConnection</code>. The
0057: * <code>Protocol</code> object represents a connection to a low-level transport
0058: * mechanism.
0059: * <p>
0060: * Optional packages, such as <code>Protocol</code>, cannot reside in
0061: * small devices.
0062: * The Generic Connection Framework allows an application to reach the
0063: * optional packages and classes indirectly. For example, an application
0064: * can be written with a string that is used to open a connection. Inside
0065: * the implementation of <code>Connector</code>, the string is mapped to a
0066: * particular implementation: <code>Protocol</code>, in this case. This allows
0067: * the implementation to be optional even though
0068: * the interface, <code>MessageConnection</code>, is required.
0069: * <p>
0070: * Closing the connection frees an instance of <code>MessageConnection</code>.
0071: * <p>
0072: * The <code>Protocol</code> class contains methods
0073: * to open and close the connection to the low-level transport mechanism. The
0074: * messages passed on the transport mechanism are defined by the
0075: * {@link MessageObject MessageObject}
0076: * class.
0077: * Connections can be made in either client mode or server mode.
0078: * <ul>
0079: * <li>Client mode connections are for sending messages only. They are
0080: * created by passing a string identifying a destination address to the
0081: * <code>Connector.open()</code> method.</li>
0082: * <li>Server mode connections are for receiving and sending messages. They
0083: * are created by passing a string that identifies a port, or equivalent,
0084: * on the local host to the <code>Connector.open()</code> method.</li>
0085: * </ul>
0086: * The class also contains methods to send, receive, and construct
0087: * <code>Message</code> objects.
0088: * <p>
0089: * <p>
0090: * This class declares that it implements <code>StreamConnection</code>
0091: * so it can intercept calls to <code>Connector.open*Stream()</code>
0092: * to throw an <code>IllegalArgumentException</code>.
0093: * </p>
0094: *
0095: */
0096: public class Protocol extends ProtocolBase {
0097:
0098: /** Connection mode. */
0099: private final int connectionMode = 0;
0100:
0101: /** Currently opened connections. */
0102: static protected Vector openconnections = new Vector();
0103:
0104: /** Name of current connection. */
0105: protected String url;
0106:
0107: /** Local handle for port number. */
0108: private int m_iport = 0;
0109:
0110: /** Count of simultaneous opened conenctions. */
0111: protected static int open_count = 0;
0112:
0113: /** Ports barred from use int the specification. */
0114: int restrictedPorts[] = { 2805, // WAP WTA secure connection-less session service
0115: 2923, // WAP WTA secure session service
0116: 2948, // WAP Push connectionless session service (client side)
0117: 2949, // WAP Push secure connectionless session service (client side)
0118: 5502, // Service Card reader
0119: 5503, // Internet access configuration reader
0120: 5508, // Dynamic Menu Control Protocol
0121: 5511, // Message Access Protocol
0122: 5512, // Simple Email Notification
0123: 9200, // WAP connectionless session service
0124: 9201, // WAP session service
0125: 9202, // WAP secure connectionless session service
0126: 9203, // WAP secure session service
0127: 9207, // WAP vCal Secure
0128: 49996, // SyncML OTA configuration
0129: 49999 // WAP OTA configuration
0130: };
0131:
0132: /** DCS: GSM Alphabet */
0133: protected static final int GSM_TEXT = 0;
0134:
0135: /** DCS: Binary */
0136: protected static final int GSM_BINARY = 1;
0137:
0138: /** DCS: Unicode UCS-2 */
0139: protected static final int GSM_UCS2 = 2;
0140:
0141: /** Creates a message connection protocol handler. */
0142: public Protocol() {
0143: super ();
0144: ADDRESS_PREFIX = "sms://";
0145: }
0146:
0147: /**
0148: * Gets the connection parameter in string mode.
0149: * @return string that contains a parameter
0150: */
0151: protected String getAppID() {
0152: if (m_iport > 0) {
0153: return new String(Integer.toString(m_iport));
0154: } else {
0155: return null;
0156: }
0157: }
0158:
0159: /**
0160: * Sets the connection parameter in string mode.
0161: * @param newValue new value of connection parameter
0162: */
0163: protected void setAppID(String newValue) {
0164: try {
0165: m_iport = Integer.parseInt(newValue);
0166: } catch (NumberFormatException exc) {
0167: m_iport = 0;
0168: }
0169: }
0170:
0171: /**
0172: * Private class to encapsulate SMSPacket data structure
0173: *
0174: */
0175: private class SMSPacket {
0176: /** Message buffer */
0177: public byte[] message;
0178: /** Buffer with sender's address */
0179: public byte[] address;
0180: /** port number */
0181: public int port;
0182: /** sent at */
0183: public long sentAt;
0184: /** Type of message */
0185: public int messageType;
0186: };
0187:
0188: /*
0189: * MessageConnection Interface
0190: */
0191:
0192: /**
0193: * Constructs a new message object of a text or binary type.
0194: * If the <code>TEXT_MESSAGE</code> constant is passed in, the
0195: * <code>TextMessage</code> interface is implemented by the created object.
0196: * If the <code>BINARY_MESSAGE</code> constant is passed in, the
0197: * <code>BinaryMessage</code> interface is implemented by the created
0198: * object.
0199: * <p>
0200: * If this method is called in a sending mode, a new <code>Message</code>
0201: * object is requested from the connection. For example:
0202: * <p>
0203: * <code>Message msg = conn.newMessage(TEXT_MESSAGE);</code>
0204: * <p>
0205: * The <code>Message</code> object that was created doesn't have the
0206: * destination address set. It's the application's responsibility to set it
0207: * before the message is sent.
0208: * <p>
0209: * If this method is called in receiving mode, the
0210: * <code>Message</code> object does have
0211: * its address set. The application can act on the object to extract
0212: * the address and message data.
0213: * <p>
0214: * <!-- The <code>type</code> parameter indicates the number of bytes
0215: * that should be
0216: * allocated for the message. No restrictions are placed on the application
0217: * for the value of <code>size</code>.
0218: * A value of <code>null</code> is permitted and creates a
0219: * <code>Message</code> object
0220: * with a 0-length message. -->
0221: *
0222: * @param type <code>TEXT_MESSAGE</code> or
0223: * <code>BINARY_MESSAGE</code>.
0224: * @return a new message.
0225: */
0226: public Message newMessage(String type) {
0227: String address = null;
0228:
0229: /*
0230: * Provide the default address from the original open.
0231: */
0232:
0233: if (((m_mode & Connector.WRITE) > 0) && (host != null)) {
0234: address = ADDRESS_PREFIX + host;
0235: if (m_iport != 0) {
0236: address = address + ":" + String.valueOf(m_iport);
0237: }
0238: }
0239:
0240: return newMessage(type, address);
0241: }
0242:
0243: /**
0244: * Constructs a new message object of a text or binary type and specifies
0245: * a destination address.
0246: * If the <code>TEXT_MESSAGE</code> constant is passed in, the
0247: * <code>TextMessage</code> interface is implemented by the created object.
0248: * If the <code>BINARY_MESSAGE</code> constant is passed in, the
0249: * <code>BinaryMessage</code> interface is implemented by the created
0250: * object.
0251: * <p>
0252: * The destination address <code>addr</code> has the following format:
0253: * </p>
0254: * <p>
0255: * <code>sms://</code><em>phone_number</em>:<em>port</em>
0256: * </p>
0257: *
0258: * @param type <code>TEXT_MESSAGE</code> or
0259: * <code>BINARY_MESSAGE</code>.
0260: * @param addr the destination address of the message.
0261: * @return a new <code>Message</code> object.
0262: */
0263: public Message newMessage(String type, String addr) {
0264: Message message = null;
0265:
0266: if (type.equals(MessageConnection.TEXT_MESSAGE)) {
0267:
0268: message = new TextObject(addr);
0269: } else {
0270: if (type.equals(MessageConnection.BINARY_MESSAGE)) {
0271:
0272: message = new BinaryObject(addr);
0273: } else {
0274: throw new IllegalArgumentException(
0275: "Message type not supported");
0276: }
0277: }
0278:
0279: return message;
0280: }
0281:
0282: /**
0283: * Receives the bytes that have been sent over the connection, constructs a
0284: * <code>Message</code> object, and returns it.
0285: * <p>
0286: * If there are no <code>Message</code>s waiting on the connection, this
0287: * method will block until a message is received, or the
0288: * <code>MessageConnection</code> is closed.
0289: *
0290: * @return a <code>Message</code> object.
0291: * @exception java.io.IOException if an error occurs while receiving a
0292: * message.
0293: * @exception java.io.InterruptedIOException if this
0294: * <code>MessageConnection</code> object is closed during this receive
0295: * method call.
0296: * @exception java.lang.SecurityException if the application does not have
0297: * permission to receive messages using the given port number.
0298: */
0299: public synchronized Message receive() throws IOException {
0300:
0301: /* Check if we have permission to recieve. */
0302: checkReceivePermission();
0303:
0304: /* Make sure the connection is still open. */
0305: ensureOpen();
0306:
0307: if (((m_mode & Connector.READ) == 0) || (host != null)) {
0308:
0309: throw new IOException("Invalid connection mode");
0310: }
0311:
0312: Message message = null;
0313: int length = 0;
0314: try {
0315:
0316: SMSPacket smsPacket = new SMSPacket();
0317:
0318: /*
0319: * Packet has been received and deleted from inbox.
0320: * Time to wake up receive thread.
0321: */
0322: // Pick up the SMS message from the message pool.
0323: length = receive0(m_iport, midletSuite.getID(), connHandle,
0324: smsPacket);
0325:
0326: if (length >= 0) {
0327: String type;
0328: boolean isTextMessage = true;
0329: if (smsPacket.messageType == GSM_BINARY) {
0330: type = MessageConnection.BINARY_MESSAGE;
0331: isTextMessage = false;
0332: } else {
0333: type = MessageConnection.TEXT_MESSAGE;
0334: isTextMessage = true;
0335: }
0336: message = newMessage(type, new String(ADDRESS_PREFIX
0337: + new String(smsPacket.address) + ":"
0338: + smsPacket.port));
0339: String messg = null;
0340: if (isTextMessage) {
0341: if (length > 0) {
0342: if (smsPacket.messageType == GSM_TEXT) {
0343: messg = new String(TextEncoder
0344: .toString(TextEncoder
0345: .decode(smsPacket.message)));
0346: } else {
0347: messg = new String(TextEncoder
0348: .toString(smsPacket.message));
0349:
0350: }
0351: } else {
0352: messg = new String("");
0353: }
0354: ((TextObject) message).setPayloadText(messg);
0355: } else {
0356: if (length > 0) {
0357: ((BinaryObject) message)
0358: .setPayloadData(smsPacket.message);
0359: } else {
0360: ((BinaryObject) message)
0361: .setPayloadData(new byte[0]);
0362: }
0363: }
0364: ((MessageObject) message)
0365: .setTimeStamp(smsPacket.sentAt);
0366: }
0367: } catch (InterruptedIOException ex) {
0368: length = 0;
0369: throw new InterruptedIOException(
0370: "MessageConnection is closed");
0371: } catch (IOException ex) {
0372: io2InterruptedIOExc(ex, "receiving");
0373: } finally {
0374: if (length < 0) {
0375: throw new InterruptedIOException(
0376: "Connection closed error");
0377: }
0378: }
0379:
0380: return message;
0381: }
0382:
0383: /**
0384: * Sends a message over the connection. This method extracts the data
0385: * payload from the <code>Message</code> object so that it can be sent as a
0386: * datagram.
0387: *
0388: * @param dmsg a <code>Message</code> object
0389: * @exception java.io.IOException if the message could not be sent or
0390: * because of network failure
0391: * @exception java.lang.IllegalArgumentException if the message is
0392: * incomplete or contains invalid information. This exception is also
0393: * thrown if the payload of the message exceeds the maximum length for
0394: * the given messaging protocol.
0395: * @exception java.io.InterruptedIOException if a timeout occurs while
0396: * either trying to send the message or if this <code>Connection</code>
0397: * object is closed during this <code>send</code> operation.
0398: * @exception java.lang.NullPointerException if the parameter is
0399: * <code>null</code>.
0400: * @exception java.lang.SecurityException if the application does not have
0401: * permission to send the message.
0402: */
0403: public void send(Message dmsg) throws IOException {
0404: String phoneNumber = null;
0405: String address = null;
0406:
0407: if (dmsg == null) {
0408: throw new NullPointerException();
0409: }
0410:
0411: if (dmsg.getAddress() == null) {
0412: throw new IllegalArgumentException();
0413: }
0414:
0415: /*
0416: * parse name into host and port
0417: */
0418: String addr = dmsg.getAddress();
0419: HttpUrl url = new HttpUrl(addr);
0420: if (url.port == -1) {
0421: /* no port supplied */
0422: url.port = 0;
0423: }
0424:
0425: /* Can not send to cbs address. */
0426: if (addr.startsWith("cbs:")) {
0427: // Can't send a CBS message.
0428: throw new IllegalArgumentException("Can't send CBS msg.");
0429: }
0430:
0431: int numSeg = numberOfSegments(dmsg);
0432: if ((numSeg <= 0) || (numSeg > 3)) {
0433: throw new IOException("Error: message is too large");
0434: }
0435:
0436: try {
0437: midletSuite.checkForPermission(Permissions.SMS_SEND,
0438: url.host, Integer.toString(numSeg));
0439: } catch (InterruptedException ie) {
0440: throw new InterruptedIOException(
0441: "Interrupted while trying "
0442: + "to ask the user permission");
0443: }
0444:
0445: ensureOpen();
0446:
0447: if ((m_mode & Connector.WRITE) == 0) {
0448:
0449: throw new IOException("Invalid mode");
0450: }
0451:
0452: int sourcePort = 0;
0453: if ((m_mode & Connector.READ) != 0 && host == null) {
0454: sourcePort = m_iport;
0455: }
0456:
0457: for (int restrictedPortIndex = 0; restrictedPortIndex < restrictedPorts.length; restrictedPortIndex++) {
0458: if (url.port == restrictedPorts[restrictedPortIndex]) {
0459: throw new SecurityException(
0460: "not allowed to send SMS messages to the restricted ports");
0461: }
0462: }
0463:
0464: int messageType = GSM_BINARY;
0465: byte[] msgBuffer = null;
0466:
0467: if (dmsg instanceof TextObject) {
0468: byte[] gsm7bytes;
0469: msgBuffer = ((TextObject) dmsg).getBytes();
0470: if (msgBuffer != null) {
0471: /*
0472: * Attempt to encode the UCS2 bytes as GSM 7-bit.
0473: */
0474: gsm7bytes = TextEncoder.encode(msgBuffer);
0475: if (gsm7bytes != null) {
0476: msgBuffer = gsm7bytes;
0477: messageType = GSM_TEXT;
0478: } else {
0479: /*
0480: * Encoding attempt failed. Send UCS2 bytes.
0481: */
0482: messageType = GSM_UCS2;
0483: }
0484: }
0485:
0486: } else if (dmsg instanceof BinaryObject) {
0487: msgBuffer = ((BinaryObject) dmsg).getPayloadData();
0488: } else {
0489: throw new IllegalArgumentException(
0490: "Message type not supported");
0491: }
0492:
0493: try {
0494: send0(connHandle, messageType, url.host, url.port,
0495: sourcePort, msgBuffer);
0496: } catch (IOException ex) {
0497: io2InterruptedIOExc(ex, "sending");
0498: }
0499: }
0500:
0501: /**
0502: * Returns how many segments in the underlying protocol would
0503: * be needed for sending the <code>Message</code> given as the parameter.
0504: *
0505: * <p>Note that this method does not actually send the message;
0506: * it will only calculate the number of protocol segments
0507: * needed for sending it.
0508: * </p>
0509: * <p>This method calculates the number of segments required
0510: * when this message is split into the protocol segments
0511: * utilizing the underlying protocol's features.
0512: * Possible implementation's limitations that may limit the number of
0513: * segments that can be sent using it are not taken into account. These
0514: * limitations are protocol specific. They are documented
0515: * with that protocol's adapter definition.
0516: * </p>
0517: * @param msg the message to be used for the calculation
0518: * @return number of protocol segments required to send the message.
0519: * If the <code>Message</code> object can't be sent using
0520: * the underlying protocol, <code>0</code> is returned.
0521: */
0522: public int numberOfSegments(Message msg) {
0523:
0524: /** The number of segments required to send the message. */
0525: int segments = 0;
0526:
0527: /* Generate the proper buffer contents and message type. */
0528: byte[] msgBuffer = null;
0529: int messageType = GSM_TEXT;
0530: if (msg instanceof TextObject) {
0531: msgBuffer = ((TextObject) msg).getBytes();
0532: if (msgBuffer != null) {
0533: /*
0534: * Attempt to encode the UCS2 bytes as GSM 7-bit.
0535: */
0536: byte[] gsm7bytes = TextEncoder.encode(msgBuffer);
0537: if (gsm7bytes != null) {
0538: msgBuffer = gsm7bytes;
0539: } else {
0540: /*
0541: * Encoding attempt failed. Use UCS2 bytes.
0542: */
0543: messageType = GSM_UCS2;
0544: }
0545: }
0546: } else if (msg instanceof BinaryObject) {
0547: msgBuffer = ((BinaryObject) msg).getPayloadData();
0548: messageType = GSM_BINARY;
0549: } else {
0550: throw new IllegalArgumentException(
0551: "Message type not supported.");
0552: }
0553:
0554: // Pick up the message length.
0555: if (msgBuffer != null) {
0556:
0557: // Parse address to see if there's a port value.
0558: boolean hasPort = false;
0559: String addr = msg.getAddress();
0560: if (addr != null) {
0561: // workaround. HttpUrl can throw IAE on zero port.
0562: try {
0563: HttpUrl url = new HttpUrl(addr);
0564: if (url.port != -1) {
0565: /* No port supplied. */
0566: hasPort = true;
0567: }
0568: } catch (IllegalArgumentException iae) {
0569: hasPort = false;
0570: }
0571:
0572: if (addr.startsWith("cbs:")) {
0573: // Can't send a CBS message.
0574: return 0;
0575: }
0576: }
0577: // Other protocols can receive the message.
0578: segments = numberOfSegments0(msgBuffer, msgBuffer.length,
0579: messageType, hasPort);
0580: }
0581:
0582: return segments;
0583: }
0584:
0585: /**
0586: * Closes the connection. Resets the connection <code>open</code> flag
0587: * to <code>false</code>. Subsequent operations on a
0588: * closed connection should throw an appropriate exception.
0589: *
0590: *
0591: * @exception IOException if an I/O error occurs
0592: */
0593: public void close() throws IOException {
0594: /*
0595: * Set m_iport to 0, in order to quit out of the while loop
0596: * in the receiver thread.
0597: */
0598: int save_iport = m_iport;
0599:
0600: m_iport = 0;
0601:
0602: synchronized (closeLock) {
0603: if (open) {
0604: /*
0605: * Reset open flag early to prevent receive0 executed by
0606: * concurrent thread to operate on partially closed
0607: * connection
0608: */
0609: open = false;
0610:
0611: close0(save_iport, connHandle, 1);
0612:
0613: setMessageListener(null);
0614:
0615: /*
0616: * Reset handle and other params to default
0617: * values. Multiple calls to close() are allowed
0618: * by the spec and the resetting would prevent any
0619: * strange behaviour.
0620: */
0621: connHandle = 0;
0622: host = null;
0623: m_mode = 0;
0624:
0625: /*
0626: * Remove this connection from the list of open
0627: * connections.
0628: */
0629: int len = openconnections.size();
0630: for (int i = 0; i < len; i++) {
0631: if (openconnections.elementAt(i) == this ) {
0632: openconnections.removeElementAt(i);
0633: break;
0634: }
0635: }
0636:
0637: open_count--;
0638: }
0639: }
0640: }
0641:
0642: /*
0643: * ConnectionBaseInterface Interface
0644: */
0645:
0646: /**
0647: * Opens a connection. This method is called from the
0648: * <code>Connector.open()</code> method to obtain the destination
0649: * address given in the <code>name</code> parameter.
0650: * <p>
0651: * The format for the <code>name</code> string for this method is:
0652: * </p>
0653: * <p>
0654: * <code>sms://<em>[phone_number</em>:<em>][port_number]</em></code>
0655: * </p>
0656: * <p>
0657: * where the <em>phone_number:</em> is optional.
0658: * If the <em>phone_number</em>
0659: * parameter is present, the connection is being opened in
0660: * client mode. This means that messages can be sent.
0661: * If the parameter is absent, the connection is being opened in
0662: * server mode. This means that messages can be sent and received.
0663: * <p>
0664: * The connection that is opened is to a low-level transport mechanism
0665: * which can be any of the following:
0666: * <ul>
0667: * <li>a datagram Short Message Peer-to-Peer (SMPP)
0668: * to a service center </li>
0669: * <li>a <code>comm</code> connection to a phone device with
0670: * AT-commands</li>
0671: * <li>a native SMS stack</li>
0672: * </ul>
0673: * Currently, the <code>mode</code> and <code>timeouts</code> parameters are
0674: * ignored.
0675: *
0676: * @param name the target of the connection
0677: * @param mode indicates whether the caller
0678: * intends to write to the connection. Currently,
0679: * this parameter is ignored.
0680: * @param timeouts indicates whether the caller
0681: * wants timeout exceptions. Currently,
0682: * this parameter is ignored.
0683: * @return this connection
0684: * @exception IOException if the connection is closed or unavailable
0685: */
0686: public Connection openPrim(String name, int mode, boolean timeouts)
0687: throws IOException {
0688:
0689: return openPrimInternal(name, mode, timeouts);
0690: }
0691:
0692: /*
0693: * StreamConnection Interface
0694: */
0695:
0696: /**
0697: * Open and return an input stream for a connection.
0698: * This method always throw
0699: * <code>IllegalArgumentException</code>.
0700: *
0701: * @return An input stream
0702: * @exception IOException If an I/O error occurs
0703: * @exception IllegalArgumentException is thrown for all requests
0704: */
0705: public InputStream openInputStream() throws IOException {
0706:
0707: throw new IllegalArgumentException("Not supported");
0708: }
0709:
0710: /**
0711: * Open and return a data input stream for a connection.
0712: * This method always throw
0713: * <code>IllegalArgumentException</code>.
0714: *
0715: * @return An input stream
0716: * @exception IOException If an I/O error occurs
0717: * @exception IllegalArgumentException is thrown for all requests
0718: */
0719: public DataInputStream openDataInputStream() throws IOException {
0720:
0721: throw new IllegalArgumentException("Not supported");
0722: }
0723:
0724: /**
0725: * Open and return an output stream for a connection.
0726: * This method always throw
0727: * <code>IllegalArgumentException</code>.
0728: *
0729: * @return An output stream
0730: * @exception IOException If an I/O error occurs
0731: * @exception IllegalArgumentException is thrown for all requests
0732: */
0733: public OutputStream openOutputStream() throws IOException {
0734:
0735: throw new IllegalArgumentException("Not supported");
0736: }
0737:
0738: /**
0739: * Open and return a data output stream for a connection.
0740: * This method always throw
0741: * <code>IllegalArgumentException</code>.
0742: *
0743: * @return an output stream
0744: * @exception IOException if an I/O error occurs
0745: * @exception IllegalArgumentException is thrown for all requests
0746: */
0747: public DataOutputStream openDataOutputStream() throws IOException {
0748:
0749: throw new IllegalArgumentException("Not supported");
0750: }
0751:
0752: /*
0753: * Protocol members
0754: */
0755:
0756: /**
0757: * Opens a connection. This is the internal entry point that
0758: * allows the CBS protocol handler to use the reserved port for
0759: * CBS emulated messages.
0760: *
0761: * @param name the target of the connection
0762: * @param mode indicates whether the caller
0763: * intends to write to the connection. Currently,
0764: * this parameter is ignored.
0765: * @param timeouts indicates whether the caller
0766: * wants timeout exceptions. Currently,
0767: * this parameter is ignored.
0768: * @return this connection
0769: * @exception IOException if the connection is closed or unavailable
0770: */
0771: public synchronized Connection openPrimInternal(String name,
0772: int mode, boolean timeouts) throws IOException {
0773:
0774: /*
0775: * If <code>host == null</code>, then we are a server endpoint at
0776: * the supplied <code>port</code>.
0777: *
0778: * If <code>host != null</code> we are a client endpoint at a port
0779: * decided by the system and the default address for
0780: * SMS messages to be sent is <code>sms://host:port</code>.
0781: */
0782:
0783: String portName = null;
0784:
0785: if ((name == null) || (name.length() <= 2)
0786: || (name.charAt(0) != '/') || (name.charAt(1) != '/')) {
0787: throw new IllegalArgumentException(
0788: "Missing protocol separator");
0789: }
0790:
0791: int colon = name.indexOf(':');
0792: if (colon > 0) {
0793: if (colon != 2) {
0794: host = name.substring(2, colon);
0795: }
0796: portName = name.substring(colon + 1);
0797: } else {
0798: if (name.length() > 2) {
0799: host = name.substring(2);
0800: }
0801: }
0802:
0803: if (host != null) {
0804: int offset = 0;
0805: int len = host.length();
0806: char c = '\0';
0807: /* Only '+' followed by 0-9 are allowed in the host field. */
0808: if (len > 0) {
0809: c = host.charAt(0);
0810: if (c == '+') {
0811: offset = 1;
0812: }
0813: for (int i = offset; i < host.length(); i++) {
0814: c = host.charAt(i);
0815: if ('0' <= c && c <= '9') {
0816:
0817: continue;
0818: } else {
0819: throw new IllegalArgumentException(
0820: "Host format");
0821: }
0822: }
0823: }
0824: }
0825:
0826: int portNumber = 0;
0827: m_iport = 0;
0828: if (portName != null) {
0829: int len = portName.length();
0830: if (len == 0) {
0831: throw new IllegalArgumentException("Port length");
0832: }
0833: /*
0834: * Add a numeric check hat the port is less than the
0835: * GSM maximum port number.
0836: */
0837: try {
0838: portNumber = Integer.parseInt(portName);
0839: m_iport = portNumber;
0840: if ((portNumber > 65535) || (portNumber < 0)) {
0841: throw new IllegalArgumentException("Port range");
0842: }
0843: } catch (NumberFormatException nfe) {
0844: throw new IllegalArgumentException("Port Number"
0845: + " formatted badly.");
0846: }
0847:
0848: }
0849:
0850: if (mode == Connector.READ && host != null && host.length() > 0) {
0851: throw new IllegalArgumentException("Cannot read on "
0852: + "client connection");
0853: }
0854:
0855: if ((mode == Connector.WRITE) && (host == null)) {
0856: /*
0857: * avoid throwing the following exception for compliance
0858: * throw new IllegalArgumentException("Missing host name");
0859: */
0860: }
0861:
0862: if ((mode != Connector.READ) && (mode != Connector.WRITE)
0863: && (mode != Connector.READ_WRITE)) {
0864:
0865: throw new IllegalArgumentException("Invalid mode");
0866: }
0867:
0868: /*
0869: * Check to see if the application has the permision to
0870: * use this connection type.
0871: */
0872: if (!openPermission) {
0873: try {
0874: midletSuite.checkForPermission(Permissions.SMS_SERVER,
0875: "sms:open");
0876: openPermission = true;
0877: } catch (InterruptedException ie) {
0878: throw new InterruptedIOException(
0879: "Interrupted while trying "
0880: + "to ask the user permission");
0881: }
0882: }
0883: /*
0884: * Check to see if this connection is already opened.
0885: */
0886: int len = openconnections.size();
0887: for (int i = 0; i < len; i++) {
0888: if (!(openconnections.elementAt(i) instanceof com.sun.midp.io.j2me.sms.Protocol)
0889: || ((Protocol) openconnections.elementAt(i)).url
0890: .equals(name)) {
0891: throw new IOException("Already opened");
0892: }
0893: }
0894:
0895: openconnections.addElement(this );
0896: url = name;
0897:
0898: try {
0899: connHandle = open0(host, midletSuite.getID(), m_iport);
0900: } catch (IOException ioexcep) {
0901: m_mode = 0;
0902: throw new IOException("SMS connection cannot be opened");
0903: } catch (OutOfMemoryError oomexcep) {
0904: m_mode = 0;
0905: throw new IOException("SMS connection cannot be opened");
0906: }
0907:
0908: open_count++;
0909: m_mode = mode;
0910: open = true;
0911:
0912: return this ;
0913: }
0914:
0915: /**
0916: * Checks internal setting of receive permission.
0917: * Called from receive and setMessageListener methods.
0918: * @exception InterruptedIOException if permission dialog
0919: * was preempted
0920: */
0921: protected void checkReceivePermission()
0922: throws InterruptedIOException {
0923: /* Check if we have permission to recieve. */
0924: if (!readPermission) {
0925: try {
0926: midletSuite.checkForPermission(Permissions.SMS_RECEIVE,
0927: "sms:receive");
0928: readPermission = true;
0929: } catch (InterruptedException ie) {
0930: throw new InterruptedIOException(
0931: "Interrupted while trying "
0932: + "to ask the user permission");
0933: }
0934: }
0935: }
0936:
0937: /**
0938: * Native finalizer
0939: */
0940: private native void finalize();
0941:
0942: /**
0943: * Native function to open sms connection
0944: *
0945: * @param host The name of the host for this connection. Can be
0946: * <code>null</code>.
0947: * @param msid Midlet suite ID, Cannot be <code>null</code>.
0948: * @param port port to open
0949: * @return returns handle to SMS connection.
0950: */
0951: private native int open0(String host, int msid, int port)
0952: throws IOException;
0953:
0954: /**
0955: * Unblock the receive thread.
0956: *
0957: * @param msid The MIDlet suite ID.
0958: *
0959: * @return returns handle to the connection.
0960: */
0961: protected int unblock00(int msid) throws IOException {
0962: return open0(null, msid, 0);
0963: }
0964:
0965: /**
0966: * Native function to close sms connection
0967: *
0968: * @param port port number to close
0969: * @param handle sms handle returned by open0
0970: * @param deRegister Deregistration appID when parameter is 1.
0971: * @return 0 on success, -1 on failure
0972: */
0973: private native int close0(int port, int handle, int deRegister);
0974:
0975: /**
0976: * Close connection.
0977: *
0978: * @param connHandle handle returned by open0
0979: * @param deRegister Deregistration appID when parameter is 1.
0980: * @return 0 on success, -1 on failure
0981: */
0982: protected int close00(int connHandle, int deRegister) {
0983: return close0(m_iport, connHandle, deRegister);
0984: }
0985:
0986: /**
0987: * Sends SMS message
0988: *
0989: * @param handle handle to SMS connection.
0990: * @param type message type, binary or text.
0991: * @param host URL of host sending message
0992: * @param destPort destination port
0993: * @param sourcePort source port
0994: * @param message message buffer
0995: * @return number of bytes sent
0996: * @exception IOException if an I/O error occurs
0997: */
0998: private native int send0(int handle, int type, String host,
0999: int destPort, int sourcePort, byte[] message)
1000: throws IOException;
1001:
1002: /**
1003: * Receives SMS message
1004: *
1005: * @param port incoming port
1006: * @param msid Midlet suite ID
1007: * @param handle handle to open SMS connection
1008: * @param smsPacket received packet
1009: * @return number of bytes received
1010: * @exception IOException if an I/O error occurs
1011: */
1012: private native int receive0(int port, int msid, int handle,
1013: SMSPacket smsPacket) throws IOException;
1014:
1015: /**
1016: * Waits until message available
1017: *
1018: * @param port incoming port
1019: * @param handle handle to SMS connection
1020: * @return 0 on success, -1 on failure
1021: * @exception IOException if an I/O error occurs
1022: */
1023: private native int waitUntilMessageAvailable0(int port, int handle)
1024: throws IOException;
1025:
1026: /**
1027: * Waits until message available
1028: *
1029: * @param handle handle to connection
1030: * @return 0 on success, -1 on failure
1031: * @exception IOException if an I/O error occurs
1032: */
1033: protected int waitUntilMessageAvailable00(int handle)
1034: throws IOException {
1035: return waitUntilMessageAvailable0(m_iport, handle);
1036: }
1037:
1038: /**
1039: * Computes the number of transport-layer segments that would be required to
1040: * send the given message.
1041: *
1042: * @param msgBuffer The message to be sent.
1043: * @param msgLen The length of the message.
1044: * @param msgType The message type: binary or text.
1045: * @param hasPort Indicates if the message includes a source or destination
1046: * port number.
1047: *
1048: * @return The number of transport-layer segments required to send the
1049: * message.
1050: */
1051: private native int numberOfSegments0(byte msgBuffer[], int msgLen,
1052: int msgType, boolean hasPort);
1053:
1054: }
|