send_sms.cs

download

/* We use the HttpUtility class from the System.Web namespace
*
* If you see of the error "'HttpUtility' is not declared", you are probably
* using a newer version of Visual Studio. You need to navigate to
* Project | <Project name> Properties | Application,
* and select e.g. ".NET Framework 4" instead of ".NET Framework 4 Client Profile" as your 'Target framework'.
*
* Next, visit Project | Add reference, and select "System.Web" (specifically
* System.Web - not System.Web.<something>).
*/

using System.Net;
using System;
using System.Web;
using System.Text;
using System.IO;
using System.Collections;

namespace SMS {
  public class SendSMS {

    static void Main( ) {
      /*
      * Simply substitute your own username, password and phone number
      * below, and run the test code:
      */
      string username = "username";
      string password = "password";
      /*
      * Your phone number, including country code, i.e. +44123123123 in this case:
      */
      string msisdn   = "447123123123";

      string url = "«EAPI URL»/submission/send_sms/2/2.0";

      /*
      * A 7-bit GSM SMS message can contain up to 160 characters (longer messages can be
      * achieved using concatenation).
      *
      * All non-alphanumeric 7-bit GSM characters are included in this example. Note that Greek characters,
      * and extended GSM characters (e.g. the caret "^"), may not be supported
      * to all networks. Please let us know if you require support for any characters that
      * do not appear to work to your network.
      */
      string seven_bit_msg = "Test message: all non-alphanumeric GSM characters: $@!#%&\",;:<>¡£¤¥§¿ÄÅÆÇÉÑÖØÜßàèéùìòå¿äöñüà\nGreek: ΩΘΔΦΓΛΩΠΨΣΘΞ";


      /*
      * A Unicode SMS can contain only 70 characters. Any Unicode character can be sent,
      * including those GSM and accented ISO-8859 European characters that are not
      * catered for by the GSM character set, but note that mobile phones are only able
      * to display certain Unicode characters, based on their geographic market.
      * Nonetheless, every mobile phone should be able to display at least the text
      * "Unicode test message:" from the test message below. Your browser may be able to
      * display more of the characters than your phone. The text of the message below is:
      */
      string unicode_msg = "Unicode test message: ☺ \nArabic: شصض\nChinese: 本网";

      /*
      * There's a number of 8 bit messages that one can send to a handset, the most popular of the lot is Service Indication(Wap Push).
      * Some other popular ones are vCards and vCalendars, headers may vary depending on which of message one opts to send.
      * The User Data Header(UDH) is solely responsible for determining which
      * type of messages will be sent to ones' handset.
      * In a nutshell, SI(service indication) messages will have, in the final message body, both the UDH
      * and WSP(Wireless Session Protocol) appended to each other forming a prefix of the ASCII string of the Hex value
      * of the actual content. For example, suppose our intended Wap message body is as follows:
      *
      * <si><indication href="http://www.bulksms.com">Visit BulkSMS.com homepage</indication></si>
      *
      * Our headers will be -- UDH + WSP = FINAL_HEADER
      * '0605040B8423F0' + 'DC0601AE' = '0605040B8423F0DC0601AE'
      *
      * The UDH contains a destination port(0B84) and the origin port(23F0)
      * the WSP is broken down into the following:
      *
      * DC - Transaction ID (used to associate PDUs)
      * 06 - PDU type (push PDU)
      * 01 - HeadersLen (total of content-type and headers, i.e. zero headers)
      * AE - Content Type: application/vnd.wap.sic
      *
      * For this example our 8 bit message(what becomes our Wap Push) will look like this:
      * $msg = '0605040B8423F0DC0601AE02056a0045c60d0362756c6b736d732e636f6d00010356697369742042756c6b534d532e636f6d20686f6d6570616765000101';
      *
      * You will only get UDH for both vCard and vCalendar type of 8 bit messages and no WSP, which will look something to this effect:
      * '06050423F4000'
      *
      * Now moving on and considering the example above, we will need to determine the type of message and get the header(s)
      * there of.
      *
      * string msg_type = "wap_push";
      * string msg_body = "<si><indication href=\"http://www.bulksms.com\">Visit BulkSMS.com homepage</indication></si>";
      * string eight_bit_msg = get_headers( msg_type ) + xml_to_wbxml( msg_body );
      */
      string eight_bit_msg = "0605040B8423F0DC0601AE02056a0045c60d0362756c6b736d732e636f6d00010356697369742042756c6b534d532e636f6d20686f6d6570616765000101";

      Hashtable result;

      /*
      * Upon a transient (retryable) error, sleep this many seconds:
      */
      int sleep_time = 3;
      /*
      * The time it takes to retry transient errors will increase with
      * each retry attempt:
      */
      int retry_growth_factor = 8;
      int num_retries = 5;

      string data = seven_bit_message( username, password, msisdn, seven_bit_msg );

      for ( int x = 0; x < num_retries; x++ ) {
        result = send_sms( data, url );
        if ((int)result["success"] == 1 ) {
          Console.WriteLine( formatted_server_response( result ) );
          break;
        }
        else {
          Console.WriteLine( formatted_server_response( result ) );
        }

        System.Threading.Thread.Sleep(sleep_time);
        sleep_time *= retry_growth_factor;
      }

      sleep_time = 3;
      data = eight_bit_message( username, password, msisdn, eight_bit_msg );
      for ( int x = 0; x < num_retries; x++ ) {
        result = send_sms( data, url );
        if ((int)result["success"] == 1 ) {
          Console.WriteLine( formatted_server_response( result ) );
          break;
        }
        else {
          Console.WriteLine( formatted_server_response( result ) );
        }

        System.Threading.Thread.Sleep(sleep_time);
        sleep_time *= retry_growth_factor;
      }

      sleep_time = 3;
      data = unicode_message( username, password, msisdn, unicode_msg );
      for ( int x = 0; x < num_retries; x++ ) {
        result = send_sms( data, url );
        if ((int)result["success"] == 1 ) {
          Console.WriteLine( formatted_server_response( result ) );
          break;
        }
        else {
          Console.WriteLine( formatted_server_response( result ) );
        }

        System.Threading.Thread.Sleep(sleep_time);
        sleep_time *= retry_growth_factor;
      }
    }

    public static string formatted_server_response( Hashtable result ) {
      string ret_string = "";
      if( (int)result["success"] == 1 ) {
        ret_string += "Success: batch ID " + (string)result["api_batch_id"] + "API message: " + (string)result["api_message"] + "\nFull details " + (string)result["details"];
      }
      else {
        ret_string += "Fatal error: HTTP status " + (string)result["http_status_code"] + " API status " + (string)result["api_status_code"] + " API message " + (string)result["api_message"] + "\nFull details " + (string)result["details"];
      }

      return ret_string;
    }

    public static Hashtable send_sms( string data, string url ) {
      string sms_result = Post(url, data);

      Hashtable result_hash = new Hashtable();

      string tmp = "";
      tmp += "Response from server: " + sms_result + "\n";
      string[] parts = sms_result.Split('|');

      string statusCode = parts[0];
      string statusString = parts[1];

      result_hash.Add("api_status_code", statusCode);
      result_hash.Add("api_message", statusString);

      if(parts.Length != 3) {
        tmp += "Error: could not parse valid return data from server.\n";
      }
      else {
        if ( statusCode.Equals("0") ) {
          result_hash.Add("success", 1);
          result_hash.Add("api_batch_id", parts[2]);
          tmp += "Message sent - batch ID " + parts[2] + "\n";
        }
        else if (statusCode.Equals("1")) {
          // Success: scheduled for later sending.
          result_hash.Add("success", 1);
          result_hash.Add("api_batch_id", parts[2]);
        }
        else {
          result_hash.Add("success", 0);
          tmp += "Error sending: status code " + parts[0] + " description: " + parts[1] + "\n";
        }
      }
      result_hash.Add("details", tmp);
      return result_hash;
    }

    public static string Post(string url, string data) {

      string result = null;
      try {
        byte[] buffer = Encoding.Default.GetBytes(data);

        HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(url);
        WebReq.Method = "POST";
        WebReq.ContentType = "application/x-www-form-urlencoded";
        WebReq.ContentLength = buffer.Length;
        Stream PostData = WebReq.GetRequestStream();

        PostData.Write(buffer, 0, buffer.Length);
        PostData.Close();
        HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
        Console.WriteLine(WebResp.StatusCode);

        Stream Response = WebResp.GetResponseStream();
        StreamReader _Response = new StreamReader(Response);
        result =  _Response.ReadToEnd();
      }
      catch (Exception ex) {
        Console.WriteLine(ex.Message);
      }
      return result.Trim()+"\n";
    }

    public static string character_resolve(string body) {
      Hashtable chrs = new Hashtable();
      chrs.Add('Ω', "Û");
      chrs.Add('Θ', "Ô");
      chrs.Add('Δ', "Ð");
      chrs.Add('Φ', "Þ");
      chrs.Add('Γ', "¬");
      chrs.Add('Λ', "Â");
      chrs.Add('Π', "º");
      chrs.Add('Ψ', "Ý");
      chrs.Add('Σ', "Ê");
      chrs.Add('Ξ', "±");

      string ret_str = "";
      foreach ( char c in body ) {
        if( chrs.ContainsKey( c ) ) {
          ret_str += chrs[ c ];
        }
        else {
          ret_str += c;
        }
      }
      return ret_str;
    }

    public static string seven_bit_message( string username, string password, string msisdn, string message ) {

      /********************************************************************
      * Construct data                                                    *
      *********************************************************************/
      /*
      * Note the suggested encoding for the some parameters, notably
      * the username, password and especially the message.  ISO-8859-1
      * is essentially the character set that we use for message bodies,
      * with a few exceptions for e.g. Greek characters. For a full list,
      * see: http://developer.bulksms.com/eapi/submission/character-encoding/
      */

      string data = "";
      data += "username="  + HttpUtility.UrlEncode(username, System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&password=" + HttpUtility.UrlEncode(password, System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&message="  + HttpUtility.UrlEncode(character_resolve(message), System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&msisdn=" + msisdn;
      data += "&want_report=1";

      return data;
    }

    public static string unicode_message( string username, string password, string msisdn, string message ) {

      /********************************************************************
      * Construct data                                                    *
      *********************************************************************/
      /*
      * Note the suggested encoding for the some parameters, notably
      * the username, password and especially the message.  ISO-8859-1
      * is essentially the character set that we use for message bodies,
      * with a few exceptions for e.g. Greek characters. For a full list,
      * see: http://developer.bulksms.com/eapi/submission/character-encoding/
      */


      string data = "";
      data += "username="  + HttpUtility.UrlEncode(username, System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&password=" + HttpUtility.UrlEncode(password, System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&message="  + stringToHex( message );
      data += "&msisdn=" + msisdn;
      data += "&dca=16bit";
      data += "&want_report=1";

      return data;
    }

    public static string eight_bit_message( string username, string password, string msisdn, string message ) {

      /********************************************************************
      * Construct data                                                    *
      *********************************************************************/
      /*
      * Note the suggested encoding for the some parameters, notably
      * the username, password and especially the message.  ISO-8859-1
      * is essentially the character set that we use for message bodies,
      * with a few exceptions for e.g. Greek characters. For a full list,
      * see: http://developer.bulksms.com/eapi/submission/character-encoding/
      */

      /*
      * In the following $udh string, 0B84 is a destination port and 23F0 is the origin port.
      */
      string udh = "0605040B8423F0";

      /*
      * $wsp_header is broken down into the following:
      *
      * DC - Transaction ID (used to associate PDUs)
      * 06 - PDU type (push PDU)
      * 01 - HeadersLen (total of content-type and headers, i.e. zero headers)
      * AE - Content Type: application/vnd.wap.sic
      */
      string wsp_header = "DC0601AE";
      string wap_push_message = udh + wsp_header + message;

      string data = "";
      data += "username="  + HttpUtility.UrlEncode(username, System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&password=" + HttpUtility.UrlEncode(password,  System.Text.Encoding.GetEncoding("ISO-8859-1"));
      data += "&message="  + wap_push_message;
      data += "&msisdn="   + msisdn;
      data += "&dca=8bit";
      data += "&want_report=1";

      return data;
    }

    public static string get_headers( string msg_type ) {
      string headers = "";
      if( msg_type == "wap_push" ) {
        string udh = "0605040B8423F0";
        string wsp = "DC0601AE";

        headers += udh + wsp;
      }
      else if( msg_type == "vCard" || msg_type == "vCalendar" ) {
        headers += "06050423F40000";
      }
      return headers;
    }

    public static string xml_to_string( string msg_body ) {
      //TODO
      /*
      * Code to convert 'msg_body' will go in here.
      */

      return "conversion";
    }

    public static string stringToHex(string s){
      string hex = "";
      foreach (char c in s)
      {
        int tmp = c;
        hex += String.Format("{0:x4}", (uint)System.Convert.ToUInt32(tmp.ToString()));
      }
      return hex;
    }
  }
}