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.pswincom;
36  
37  import java.io.BufferedReader;
38  import java.io.ByteArrayOutputStream;
39  import java.io.FileOutputStream;
40  import java.io.IOException;
41  import java.io.InputStream;
42  import java.io.InputStreamReader;
43  import java.io.OutputStream;
44  import java.io.StringWriter;
45  import java.net.Socket;
46  import java.util.Properties;
47  
48  import javax.xml.parsers.SAXParser;
49  import javax.xml.parsers.SAXParserFactory;
50  
51  import org.marre.sms.SmsAddress;
52  import org.marre.sms.SmsConstants;
53  import org.marre.sms.SmsDcs;
54  import org.marre.sms.SmsException;
55  import org.marre.sms.SmsMessage;
56  import org.marre.sms.SmsPdu;
57  import org.marre.sms.SmsPduUtil;
58  import org.marre.sms.SmsTextMessage;
59  import org.marre.sms.SmsUserData;
60  import org.marre.sms.transport.SmsTransport;
61  import org.marre.sms.transport.clickatell.ClickatellTransport;
62  import org.marre.util.IOUtil;
63  import org.marre.util.StringUtil;
64  import org.slf4j.Logger;
65  import org.slf4j.LoggerFactory;
66  import org.xml.sax.InputSource;
67  
68  /***
69   * Simple transport for the pswin xml protocol.
70   * 
71   * See http://www.pswin.com/ for more information.
72   * 
73   * <pre>
74   * Available properties:
75   * smsj.pswincom.username
76   * smsj.pswincom.password
77   * smsj.pswincom.server - server address (default is "sms.pswin.com")
78   * smsj.pswincom.port - port (default is "1111")
79   * </pre>
80   *  
81   * @author Markus
82   * @version $Id: PsWinXmlTransport.java,v 1.10 2005/11/26 16:24:23 c95men Exp $
83   */
84  public class PsWinXmlTransport implements SmsTransport
85  {
86      private static Logger log_ = LoggerFactory.getLogger(PsWinXmlTransport.class);
87      
88      private String username_;
89      private String password_;
90      
91      private String server_;
92      private int port_;
93  
94      /***
95       * Initializes the pswin transport.
96       * 
97       * @see org.marre.sms.transport.SmsTransport#init(java.util.Properties)
98       */
99      public void init(Properties props) throws SmsException
100     {
101         username_ = props.getProperty("smsj.pswincom.username");
102         password_ = props.getProperty("smsj.pswincom.password");
103         server_ = props.getProperty("smsj.pswincom.server", "sms.pswin.com");
104         port_ = Integer.parseInt(props.getProperty("smsj.pswincom.port", "1111"));
105 
106         log_.debug("init() : username = " + username_);
107         log_.debug("init() : password = " + password_);
108         log_.debug("init() : server = " + server_);
109         log_.debug("init() : port = " + port_);
110         
111         if ((username_ == null) || (password_ == null))
112         {
113             throw new SmsException("Incomplete login information for pswincom");
114         }
115     }
116 
117     private void addMsg(StringWriter xmlStringWriter, SmsPdu smsPdu, SmsAddress dest, SmsAddress sender) 
118         throws SmsException
119     {
120         SmsUserData userData = smsPdu.getUserData();
121         
122         // <MSG>
123         xmlStringWriter.write("<MSG>\r\n");
124         // <RCPREQ>Y</RCPREQ>
125         xmlStringWriter.write("<RCPREQ>Y</RCPREQ>\r\n");
126 
127         switch (smsPdu.getDcs().getAlphabet())
128         {
129         case SmsDcs.ALPHABET_UCS2:
130             // <OP>9</OP>
131             xmlStringWriter.write("<OP>9</OP>\r\n");
132             // <TEXT>hex-text</TEXT>
133             xmlStringWriter.write("<TEXT>");
134             xmlStringWriter.write(StringUtil.bytesToHexString(userData.getData()));
135             xmlStringWriter.write("</TEXT>\r\n");
136             break;
137 
138         case SmsDcs.ALPHABET_GSM:
139             // <TEXT>txt</TEXT>
140             xmlStringWriter.write("<TEXT>");
141             xmlStringWriter.write(SmsPduUtil.readSeptets(userData.getData(), userData.getLength()));
142             xmlStringWriter.write("</TEXT>\r\n");
143             break;
144 
145         case SmsDcs.ALPHABET_8BIT:
146             // <OP>8</OP>
147             xmlStringWriter.write("<OP>8</OP>\r\n");
148             // <TEXT>udh-and-ud</TEXT>
149             xmlStringWriter.write("<TEXT>");
150             xmlStringWriter.write(StringUtil.bytesToHexString(smsPdu.getUserDataHeaders())
151                     + StringUtil.bytesToHexString(userData.getData()));
152             xmlStringWriter.write("</TEXT>\r\n");
153             break;
154 
155         default:
156             throw new SmsException("Unsupported alphabet");
157         }
158 
159         // <RCV>434343434</RCV>
160         xmlStringWriter.write("<RCV>");
161         xmlStringWriter.write(dest.getAddress());
162         xmlStringWriter.write("</RCV>\r\n");
163 
164         if (sender != null)
165         {
166             // <SND>434344</SND>
167             xmlStringWriter.write("<SND>");
168             xmlStringWriter.write(sender.getAddress());
169             xmlStringWriter.write("</SND>\r\n");
170         }
171 
172         if (smsPdu.getDcs().getMessageClass() == SmsDcs.MSG_CLASS_0)
173         {
174             // <CLASS>0</CLASS>
175             xmlStringWriter.write("<CLASS>");
176             xmlStringWriter.write("0");
177             xmlStringWriter.write("</CLASS>\r\n");
178         }
179 
180         // </MSG>
181         xmlStringWriter.write("</MSG>\r\n");
182     }
183 
184     private void addTextMsg(StringWriter xmlStringWriter, SmsTextMessage msg, SmsAddress dest, SmsAddress sender) 
185         throws SmsException
186     {
187         SmsUserData userData = msg.getUserData();
188 
189         // <MSG>
190         xmlStringWriter.write("<MSG>\r\n");
191 
192         switch (userData.getDcs().getAlphabet())
193         {
194         case SmsDcs.ALPHABET_UCS2:
195             // <OP>9</OP>
196             xmlStringWriter.write("<OP>9</OP>\r\n");
197             // <TEXT>hex-text</TEXT>
198             xmlStringWriter.write("<TEXT>");
199             xmlStringWriter.write(StringUtil.bytesToHexString(userData.getData()));
200             xmlStringWriter.write("</TEXT>\r\n");
201             break;
202 
203         case SmsDcs.ALPHABET_GSM:
204             // <TEXT>txt</TEXT>
205             xmlStringWriter.write("<TEXT>");
206             xmlStringWriter.write(msg.getText());
207             xmlStringWriter.write("</TEXT>\r\n");
208             break;
209 
210         default:
211             throw new SmsException("Unsupported alphabet");
212         }
213 
214         // <RCV>434343434</RCV>
215         xmlStringWriter.write("<RCV>");
216         xmlStringWriter.write(dest.getAddress());
217         xmlStringWriter.write("</RCV>\r\n");
218 
219         if (sender != null)
220         {
221             // <SND>434344</SND>
222             xmlStringWriter.write("<SND>");
223             xmlStringWriter.write(sender.getAddress());
224             xmlStringWriter.write("</SND>\r\n");
225         }
226 
227         if (userData.getDcs().getMessageClass() == SmsDcs.MSG_CLASS_0)
228         {
229             // <CLASS>0</CLASS>
230             xmlStringWriter.write("<CLASS>");
231             xmlStringWriter.write("0");
232             xmlStringWriter.write("</CLASS>\r\n");
233         }
234 
235         // </MSG>
236         xmlStringWriter.write("</MSG>\r\n");
237     }
238 
239     /***
240      * Creates a pswin xml document and writes it to the given outputstream.
241      * 
242      * @param os
243      * @param msg
244      * @param dest
245      * @param sender
246      * @throws IOException
247      * @throws SmsException
248      */
249     private void writeXmlTo(OutputStream os, SmsMessage msg, 
250                               SmsAddress dest, SmsAddress sender)
251             throws IOException, SmsException
252     {
253         StringWriter xmlWriter = new StringWriter(1024);
254 
255         // <?xml version="1.0"?>
256         // <SESSION>
257         // <CLIENT>$myUsername</CLIENT>
258         // <PW>$myPassword</PW>
259         // <MSGLST>
260         xmlWriter.write("<?xml version=\"1.0\"?>\r\n");
261         xmlWriter.write("<SESSION>\r\n");
262         xmlWriter.write("<CLIENT>" + username_ + "</CLIENT>\r\n");
263         xmlWriter.write("<PW>" + password_ + "</PW>\r\n");
264         xmlWriter.write("<MSGLST>\r\n");
265 
266         // <MSG>...</MSG>
267         if (msg instanceof SmsTextMessage)
268         {
269             addTextMsg(xmlWriter, (SmsTextMessage) msg, dest, sender);
270         }
271         else
272         {
273             SmsPdu[] msgPdu = msg.getPdus();
274             for (int i = 0; i < msgPdu.length; i++)
275             {
276                 addMsg(xmlWriter, msgPdu[i], dest, sender);
277             }
278         }
279 
280         // </MSGLST>
281         // </SESSION>
282         xmlWriter.write("</MSGLST>\r\n");
283         xmlWriter.write("</SESSION>\r\n");
284 
285         // Finally write XML to stream
286         String xmlDoc = xmlWriter.toString();
287         os.write(xmlDoc.getBytes());
288     }
289 
290     /***
291      * Sends the given xml request to pswin for processing.
292      * 
293      * @param xmlReq
294      * @throws IOException
295      * @throws SmsException
296      */
297     private void sendReqToPsWinCom(byte[] xmlReq) throws IOException, SmsException
298     {
299         Socket xmlSocket = new Socket(server_, port_);
300 
301         // Send request
302         OutputStream os = xmlSocket.getOutputStream();
303         os.write(xmlReq);
304 
305         // Get response
306         InputStream is = xmlSocket.getInputStream();
307         
308         // Parse response
309         PsWinXmlResponseParser responseParser = new PsWinXmlResponseParser(is);
310         responseParser.parse();
311 
312         // Verify that we could logon correctly
313         if (! responseParser.getLogon().equals("OK"))
314         {
315             throw new SmsException("Failed to send message: " + responseParser.getReason());
316         }
317     }
318 
319     /***
320      * Send.
321      * 
322      * @param msg 
323      * @param dest 
324      * @param sender 
325      * @return Internal message id. 
326      * @throws SmsException 
327      * @throws IOException 
328      * 
329      * @see org.marre.sms.transport.SmsTransport#send()
330      */
331     public String send(SmsMessage msg, SmsAddress dest, SmsAddress sender) throws SmsException, IOException
332     {
333         byte[] xmlReq;
334         
335         if (dest.getTypeOfNumber() == SmsConstants.TON_ALPHANUMERIC)
336         {
337             throw new SmsException("Cannot sent SMS to ALPHANUMERIC address");
338         }
339 
340         try
341         {
342             ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
343 
344             // Create xml document
345             writeXmlTo(baos, msg, dest, sender);
346             baos.close();
347             
348             xmlReq = baos.toByteArray();
349         }
350         catch (IOException ex)
351         {
352             throw new SmsException("Failed to build xml request", ex);
353         }
354 
355         // Send req
356         sendReqToPsWinCom(xmlReq);
357         
358         // TODO: Return an internal message id
359         return null;
360     }
361 
362     /***
363      * Connect.
364      * 
365      * @see org.marre.sms.transport.SmsTransport#connect()
366      */
367     public void connect()
368     {
369         // Empty
370     }
371     
372     /***
373      * Disconnect.
374      * 
375      * @see org.marre.sms.transport.SmsTransport#disconnect()
376      */
377     public void disconnect()
378     {
379         // Empty
380     }
381 
382     /***
383      * Ping.
384      * 
385      * @see org.marre.sms.transport.SmsTransport#ping()
386      */
387     public void ping()
388     {
389         // Empty
390     }
391 }