View Javadoc

1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is "SMS Library for the Java platform".
15   *
16   * The Initial Developer of the Original Code is Markus Eriksson.
17   * Portions created by the Initial Developer are Copyright (C) 2002
18   * the Initial Developer. All Rights Reserved.
19   *
20   * Contributor(s):
21   *
22   * Alternatively, the contents of this file may be used under the terms of
23   * either the GNU General Public License Version 2 or later (the "GPL"), or
24   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25   * in which case the provisions of the GPL or the LGPL are applicable instead
26   * of those above. If you wish to allow use of your version of this file only
27   * under the terms of either the GPL or the LGPL, and not to allow others to
28   * use your version of this file under the terms of the MPL, indicate your
29   * decision by deleting the provisions above and replace them with the notice
30   * and other provisions required by the GPL or the LGPL. If you do not delete
31   * the provisions above, a recipient may use your version of this file under
32   * the terms of any one of the MPL, the GPL or the LGPL.
33   *
34   * ***** END LICENSE BLOCK ***** */
35  package org.marre.sms.transport.ucp;
36  
37  import java.io.DataInputStream;
38  import java.io.DataOutputStream;
39  import java.io.IOException;
40  import java.net.Socket;
41  import java.util.Properties;
42  
43  import org.marre.sms.SmsAddress;
44  import org.marre.sms.SmsConstants;
45  import org.marre.sms.SmsDcs;
46  import org.marre.sms.SmsException;
47  import org.marre.sms.SmsMessage;
48  import org.marre.sms.SmsPdu;
49  import org.marre.sms.SmsPduUtil;
50  import org.marre.sms.transport.SmsTransport;
51  import org.marre.util.StringUtil;
52  
53  /***
54   * An SmsTransport that sends the SMS through an UCP SMSC
55   * 
56   * 
57   * 
58   * @author Markus Eriksson
59   * @version $Id: UcpTransport.java,v 1.16 2005/11/26 16:37:14 c95men Exp $
60   */
61  public class UcpTransport implements SmsTransport
62  {
63      private String ucpServerName_;
64      private int ucpServerPort_;
65      private String ucp60Uid_;
66      private String ucp60Pwd_;
67      private boolean doUcp60Login_;
68  
69      private Socket ucpSocket_;
70      private DataOutputStream ucpOs_;
71      private DataInputStream ucpIs_;
72  
73      public UcpTransport()
74      {
75      }
76  
77      /***
78       * Initializes the class with the properties specified
79       * 
80       * @param props
81       *            <b>smsj.ucp.ip.host </b>: the ip address or dns name of the
82       *            UCP server <br>
83       *            <b>smsj.ucp.ip.port </b>: the ip port of the UCP server <br>
84       *            <b>smsj.ucp.ucp60.uid </b>: the UCP60 user id <br>
85       *            <b>smsj.ucp.ucp60.password </b>: the UCP60 password</br>
86       * 
87       * @throws SmsException
88       */
89      public void init(Properties props) throws SmsException
90      {
91          //Liquidterm: added properties support, aligned some member names to
92          //the general coding style of the project
93          //TODO: Add properties strict checking
94  
95          ucpServerName_ = props.getProperty("smsj.ucp.ip.host");
96          ucpServerPort_ = Integer.parseInt(props.getProperty("smsj.ucp.ip.port"));
97          ucp60Uid_ = props.getProperty("smsj.ucp.ucp60.uid");
98          ucp60Pwd_ = props.getProperty("smsj.ucp.ucp60.password");
99  
100         if (ucp60Uid_ == null || ucp60Pwd_ == null)
101         {
102             doUcp60Login_ = false;
103         }
104         else if ("".equals(ucp60Uid_))
105         {
106             throw new SmsException("UCP Transport: empty UCP60 username");
107         }
108         else
109         {
110             doUcp60Login_ = true;
111         }
112     }
113 
114     public void connect() throws SmsException, IOException
115     {
116         // Connect to the UCP server
117         ucpSocket_ = new Socket(ucpServerName_, ucpServerPort_);
118         ucpOs_ = new DataOutputStream(ucpSocket_.getOutputStream());
119         ucpIs_ = new DataInputStream(ucpSocket_.getInputStream());
120         
121         //Logging into the Remote Host via UCP 60;
122         //TODO: Add proper failure handling
123         if (doUcp60Login_)
124         {
125             byte[] loginCmd = buildLogin(ucp60Uid_, ucp60Pwd_);
126             String response = sendUcp(loginCmd);
127             System.err.println("SMSC response: " + response);
128         }
129     }
130 
131     public String send(SmsMessage msg, SmsAddress theDest, SmsAddress sender) throws SmsException, IOException
132     {
133         SmsPdu[] msgPdu = null;
134 
135         if (theDest.getTypeOfNumber() == SmsConstants.TON_ALPHANUMERIC)
136         {
137             throw new SmsException("Cannot sent SMS to ALPHANUMERIC address");
138         }
139 
140         msgPdu = msg.getPdus();
141         for (int i = 0; i < msgPdu.length; i++)
142         {
143             boolean moreToSend = (i < (msgPdu.length - 1));
144             byte[] submitCmd = buildSubmit(msgPdu[i], moreToSend, theDest, sender);
145             String response = sendUcp(submitCmd);
146             System.err.println("SMSC response: " + response);
147         }
148         
149         return null;
150     }
151 
152     /***
153      * Building the Login Stream
154      * 
155      * @author Lorenz Barth
156      * @throws SmsException
157      * @param userid
158      * @param pwd
159      */
160     public byte[] buildLogin(String userid, String pwd) throws SmsException
161     {
162         UCPSeries60 ucplogin = new UCPSeries60(UCPSeries60.OP_OPEN_SESSION);
163 
164         ucplogin.setTRN(0x01);
165         ucplogin.setField(UCPSeries60.FIELD_OADC, userid);
166         ucplogin.setField(UCPSeries60.FIELD_OTON, "6");
167         ucplogin.setField(UCPSeries60.FIELD_ONPI, "5");
168         ucplogin.setField(UCPSeries60.FIELD_STYP, "1");
169         ucplogin.setField(UCPSeries60.FIELD_VERS, "0100");
170         ucplogin.setField(UCPSeries60.FIELD_PWD, StringUtil.bytesToHexString(SmsPduUtil.toGsmCharset(pwd)));
171 
172         return ucplogin.getCommand();
173     }
174 
175     public byte[] buildSubmit(SmsPdu pdu, boolean moreToSend, SmsAddress dest, SmsAddress sender)
176             throws SmsException
177     {
178         String ud;
179         byte[] udhData;
180         UcpSeries50 ucpSubmit = new UcpSeries50(UcpSeries50.OP_SUBMIT_SHORT_MESSAGE);
181 
182         byte[] udh = pdu.getUserDataHeaders();
183         boolean isSeptets = (pdu.getDcs().getAlphabet() == SmsDcs.ALPHABET_GSM);
184         int udBits;
185 
186         // FIXME: TRN
187         ucpSubmit.setTRN(0x01);
188 
189         // OTOA = Originator Type Of Address (1139 = OadC is set to NPI
190         // telephone and TON international, 5039 The OAdC contains an
191         // alphanumeric address)
192         // OAdC = Address code originator
193         if (sender.getTypeOfNumber() == SmsConstants.TON_ALPHANUMERIC)
194         {
195             String addr = sender.getAddress();
196             if (addr.length() > 11)
197             {
198                 throw new SmsException("Max alphanumeric Originator Address Code length exceded (11)");
199             }
200 
201             // Changed by LB. The Alphanumeric Sender was not set correctly
202             String codedaddr = StringUtil.bytesToHexString(SmsPduUtil.getSeptets(addr));
203             int x = codedaddr.length();
204             StringBuffer sb = new StringBuffer("00");
205             sb.replace(2 - Integer.toHexString(x).toUpperCase().length(), 2, Integer.toHexString(x).toUpperCase());
206 
207             ucpSubmit.setField(UcpSeries50.FIELD_OADC, sb.toString().concat(codedaddr));
208             ucpSubmit.setField(UcpSeries50.FIELD_OTOA, "5039");
209 
210         }
211         else
212         {
213             ucpSubmit.setField(UcpSeries50.FIELD_OTOA, "1139");
214             ucpSubmit.setField(UcpSeries50.FIELD_OADC, sender.getAddress());
215         }
216 
217         // AdC = Address code recipient for the SM
218         ucpSubmit.setField(UcpSeries50.FIELD_ADC, dest.getAddress());
219         if (pdu.getUserDataHeaders() == null) // Handel Messages without UDH
220         {
221             switch (pdu.getDcs().getAlphabet())
222             {
223             case SmsDcs.ALPHABET_GSM:
224                 System.out.println("GSM Message without UDH");
225                 ucpSubmit.setField(UcpSeries50.FIELD_MT, "3");
226                 String msg = SmsPduUtil.readSeptets(pdu.getUserData().getData(), pdu.getUserData().getLength());
227                 ucpSubmit.setField(UcpSeries50.FIELD_MSG, StringUtil.bytesToHexString(SmsPduUtil.toGsmCharset(msg)));
228                 System.out.println(msg.length());
229                 break;
230             case SmsDcs.ALPHABET_8BIT:
231                 throw new SmsException(" 8Bit Messages without UDH are not Supported");
232             case SmsDcs.ALPHABET_UCS2:
233                 System.out.println("UCS2 Message without UDH");
234                 ud = StringUtil.bytesToHexString(pdu.getUserData().getData());
235                 ucpSubmit.setField(UcpSeries50.FIELD_MSG, ud);
236                 //Numer of of bits in Transperent Data Message
237                 udBits = pdu.getUserData().getLength() * ((isSeptets) ? 7 : 8);
238                 ucpSubmit.setField(UcpSeries50.FIELD_NB, StringUtil.intToString(udBits, 4));
239                 // Set message Type fix to 4
240                 ucpSubmit.setField(UcpSeries50.FIELD_MT, "4");
241                 ucpSubmit.clearXSer();
242                 ucpSubmit.addXSer(UcpSeries50.XSER_TYPE_DCS, pdu.getDcs().getValue());
243                 break;
244             default:
245                 throw new SmsException("Unsupported data coding scheme");
246             }
247         }
248         else
249         {
250             switch (pdu.getDcs().getAlphabet())
251             {
252             case SmsDcs.ALPHABET_GSM:
253                 throw new SmsException("Cannot send 7 bit encoded messages with UDH");
254             case SmsDcs.ALPHABET_8BIT:
255                 ud = StringUtil.bytesToHexString(pdu.getUserData().getData());
256                 udhData = pdu.getUserDataHeaders();
257                 // Add length of udh
258                 String udhStr = StringUtil.bytesToHexString(new byte[]{(byte) (udhData.length)});
259                 udhStr += StringUtil.bytesToHexString(udhData);
260 
261                 ucpSubmit.setField(UcpSeries50.FIELD_MSG, ud);
262                 //Numer of of bits in Transperent Data Message
263                 udBits = pdu.getUserData().getLength() * ((isSeptets) ? 7 : 8);
264                 ucpSubmit.setField(UcpSeries50.FIELD_NB, StringUtil.intToString(udBits, 4));
265                 // Set message Type fix to 4
266                 ucpSubmit.setField(UcpSeries50.FIELD_MT, "4");
267                 // Store the UDH
268                 ucpSubmit.clearXSer();
269                 ucpSubmit.addXSer(UcpSeries50.XSER_TYPE_DCS, pdu.getDcs().getValue());
270                 ucpSubmit.addXSer(UcpSeries50.XSER_TYPE_UDH, udhData);
271                 break;
272             case SmsDcs.ALPHABET_UCS2:
273                 throw new SmsException(" UCS2 Messages are currently not Supportet ");
274             default:
275                 throw new SmsException("Unsupported data coding scheme");
276             }
277         }
278         // XSer = Extra Services
279         //        ucpSubmit.clearXSer();
280         //        ucpSubmit.addXSer(UcpSeries50.XSER_TYPE_DCS, dcs);
281         //        if (udh != null)
282         //
283         //        // NB = Number of bits in TMsg
284         //        udBits = pdu.getUserDataLength() * ((isSeptets) ? 7 : 8);
285         //        udBits = pdu.getUserDataLength();
286         //        ucpSubmit.setField(UcpSeries50.FIELD_NB,
287         // StringUtil.intToString(udBits, 4));
288         // ucpSubmit.setField(UcpSeries50.FIELD_Msg,
289         // StringUtil.bytesToHexString(pdu.getUserData()));
290         //        / MMS = More messages to send
291         if (moreToSend)
292         {
293             ucpSubmit.setField(UcpSeries50.FIELD_MMS, "1");
294         }
295 
296         return ucpSubmit.getCommand();
297     }
298 
299     public void ping() throws SmsException
300     {
301     }
302 
303     /***
304      * Closing Socket and Streams
305      * 
306      * @author Lorenz Barth
307      * @throws SmsException
308      *  
309      */
310     public void disconnect() throws SmsException, IOException
311     {
312         ucpOs_.close();
313         ucpIs_.close();
314         ucpSocket_.close();
315     }
316 
317     /***
318      * This method is sending the Data to over the existing Connection and
319      * recives the answer, the Answer is returned as a String.
320      * 
321      * @author Lorenz Barth
322      * @param data
323      * @throws SmsException
324      * @throws IOException 
325      */
326     public String sendUcp(byte[] data) throws SmsException, IOException
327     {
328         if (!ucpSocket_.isConnected() || ucpOs_ == null || ucpIs_ == null)
329         {
330             throw new SmsException("Please Connect first");
331         }
332 
333         System.out.println("SMSC send: " + new String(data, 0, data.length));
334         StringBuffer strBuf;
335 
336         ucpOs_.write(data);
337         ucpOs_.flush();
338 
339         byte[] b = new byte[1];
340 
341         if ((b[0] = ucpIs_.readByte()) != 2)
342         {
343             System.out.println("SendSMS.send: The SMSC sends a bad reply");
344             throw new SmsException("The SMSC sends a bad reply");
345         }
346 
347         strBuf = new StringBuffer();
348 
349         while ((b[0] = ucpIs_.readByte()) != 3)
350         {
351             strBuf.append(new String(b));
352         }
353 
354         // Return the String
355         return strBuf.toString();
356     }
357 }