Zeep Mobile: SMS with Ads

I recently started working on integrating Zeep Mobile into an app. The documentation provided by Zeep is not the best or accurate but they do provide source code examples in…python, pearl, java. I asked about c# and the response was “i’m sure someone has posted something, search the group”. Well, no-one posted a solution so I went about coding and iteratively developing the code to send an SMS. Running into an issue, I even tried StackOverflow but that wasn’t too helpful either.

Well I finally managed to get my code working. Here is some sample c# code to send messages using the zeep framework.

I hope you all looking for c# code find this helpful.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Web;
using System.Web.Handlers;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace ConsoleApplication1
{
class Program
{
public static string API_KEY = “YOUR_API_KEY_GOES_HERE! INCLUDE DASHES!”;
public static string SECRET_ACCESS_KEY = “YOUR_SECRET_KEY_GOES_HERE!”;

static void Main(string[] args)
{
Console.WriteLine(“BLAST – \r\n\r\n”);
BlastTcpPost();

Console.WriteLine(“SEND – \r\n\r\n”);
SendTcpPost();
}

///

/// Send a BLAST to all users in your ZEEP account.
///

public static void BlastTcpPost()
{
SendSMS(
https://api.zeepmobile.com/messaging/2008-07-14/blast_message”, // URL for Send_Message
“You are on blast”, // Message to send
string.Empty // No UserId to send.
);
}

///

/// Send a single message to a user in your ZEEP account.
///

public static void SendTcpPost()
{
// Note:- 22 I use for the UserId is just a user I have signed up. Yours may be different and you
// might want to pass that in as a parameter.

SendSMS(
https://api.zeepmobile.com/messaging/2008-07-14/send_message”, // URL for Send_Message
“You are a user…good job!”, // Message to send
“22” // User Id in your system.
);

}

///

/// Uses a TCPClient and SSLStream to perform a POST.
///

/// URL that the POST must be directed to. /// Message that is to be sent. /// UserId in your Zeep System. Only required if your sending a Single Message to a User.
/// Otherwise, just send a string.Empty. /// Response from the server. (although it will write the response to console)
public static string SendSMS(string requestUrl, string body, string user)
{
string parameters = “”;
string requestHeaders = “”;
string responseData = “”;

// FORMAT must be Sun, 06 Nov 1994 08:49:37 GMT
string http_date = DateTime.UtcNow.ToString(“r”);

// Clean the text to send
body = HttpUtility.UrlEncode(body, System.Text.Encoding.UTF8);

if (user.Length > 0) parameters += “user_id=” + user + “&”;
if (body.Length > 0) parameters += “body=” + body;

// String that will be converted into a signature.
string canonicalString = API_KEY + http_date + parameters;

//————START HASH COMPUTATION———————
// Compute the Base64 HMACSHA1 value
HMACSHA1 hmacsha1 = new HMACSHA1(SECRET_ACCESS_KEY.ToByteArray());

// Compute the hash of the input file.
byte[] hashValue = hmacsha1.ComputeHash(canonicalString.ToByteArray());

String b64Mac = hashValue.ToBase64String();
String authentication = String.Format(“Zeep {0}:{1}”, API_KEY, b64Mac);
//———–END HASH COMPUTATION————————

string auth = String.Format(“Zeep {0}:{1}”, API_KEY, b64Mac);

System.Uri uri = new Uri(requestUrl);
System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(uri.Host, uri.Port);
string requestMethod = “POST ” + uri.LocalPath + ” HTTP/1.1\r\n”;

// Set Headers for the POST message
requestHeaders += “Host: api.zeepmobile.com\r\n”;
requestHeaders += “Authorization: ” + auth + “\r\n”;
requestHeaders += “Date: ” + http_date + “\r\n”;
requestHeaders += “Content-Type: application/x-www-form-urlencoded\r\n”;
requestHeaders += “Content-Length: ” + parameters.ToByteArray().Length + “\r\n”;
requestHeaders += “\r\n”;

// Get the data to be sent as a byte array.
Byte[] data = System.Text.Encoding.UTF8.GetBytes(requestMethod + requestHeaders + parameters + “\r\n”);
// Send the message to the connected TcpServer.
NetworkStream stream = client.GetStream();

// SSL Authentication is used because the Server requires https.
System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream(
stream,
false,
new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate));
sslStream.AuthenticateAsClient(uri.Host);

// Send the data over the SSL stream.
sslStream.Write(data, 0, data.Length);
sslStream.Flush();

// Receive the TcpServer.response.
for (int i = 0; i < 100; i++) { if (stream.DataAvailable) { break; } System.Threading.Thread.Sleep(100); } Byte[] bytes = new byte[1024]; System.Text.StringBuilder sb = new System.Text.StringBuilder(); while (stream.DataAvailable) { int count = sslStream.Read(bytes, 0, 1024); if (count == 0) { break; } sb.Append(System.Text.Encoding.UTF8.GetString(bytes, 0, count)); } responseData = sb.ToString(); Console.WriteLine(responseData); // Close everything. client.Close(); return responseData; } // The following method is invoked by the RemoteCertificateValidationDelegate. // We want to make sure the SSL has no Policy errors and is safe. public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // Somehow the cert always has PolicyErrors so I am returning true regardless. return true; //if (sslPolicyErrors == SslPolicyErrors.None) // return true; //Console.WriteLine("Certificate error: {0}", sslPolicyErrors); //// Do not allow this client to communicate with unauthenticated servers. //return false; } } public static class Extensions { public static byte[] ToByteArray(this string input) { UTF8Encoding encoding = new UTF8Encoding(); return encoding.GetBytes(input); } public static string ToBase64String(this byte[] input) { return Convert.ToBase64String(input); } } } [/sourcecode]

Advertisements
Tagged , , , , , , , , , , , ,

15 thoughts on “Zeep Mobile: SMS with Ads

  1. Ed Greenberg says:

    First, THANK YOU SO MUCH FOR SHARING THIS!

    Second, I think there is one change that should be made:

    On line 105:

    requestHeaders += “Date: ” + DateTime.UtcNow.ToString(“r”) + “\r\n”;

    I think it would be better if it said:

    requestHeaders += “Date: ” + http_date + “\r\n”;

    Third, I’m getting:

    400 InvalidSubscription The subscrtiption specified is not active or is blocking access from your application.

    Which subscription would this be? The user_id? My developer subscription?

    Please help if you can πŸ™‚

    • aboutdev says:

      Hi Ed. Glad to help with the code example. You are absolutely correct. It should be changed to http_date instead of recalculating it. Zeep rejects messages that have a date different to what they expect the UTC date to be so its important to keep dates uniform. I will make the change to the code. Thanks for the feedback. πŸ™‚

  2. Ed Greenberg says:

    Answering my own question, it’s the subscription referred to by the user_id πŸ˜€

  3. Daryll Herberger says:

    Aboutdev, you rock. This saves me an unbelievable amount of time.

    Also, I am guessing that the reason I am getting the same “InvalidSubscription” message received by Ed is due to Zeep blocking requests from anything but the domain registered for the specific API/secret key. For obvious reasons, the registered domain is not my dev machine. πŸ™‚

    • aboutdev says:

      Thanks Daryll. Yes the request must originate from the domain you registered. Also timestamps used must also be up to date so ensure that your server is updating time regularly.

  4. Arash says:

    You are a life saver! Now let me tell you why… I’m creating this ASP.Net website that has some texting features, and I’ve created the whole thing, only to realize stupid .Net does not allow manual manipulation of the Date header, without which Zeep wouldn’t work! It was really driving me nuts, till I finally found your entry. Zeep must post your article on their homepage!

    However, I caught a little problem in your code, and that is the user_id must also be URL Encoded (according to Simon Wex, here: http://groups.google.com/group/zeep-mobile/browse_thread/thread/a15e54affab3d570) and so, your line:

    // Clean the text to send
    body = HttpUtility.UrlEncode(body, System.Text.Encoding.UTF8);

    I also added this underneath:
    user = HttpUtility.UrlEncode(user, System.Text.Encoding.UTF8);

    And it works great. This takes care of the situation where the user_id is specified with the preceding plus sign (i.e. +1xxxyyyzzzz)

    Well, thank you so much for this great post, and I hope it becomes a bit more visible in search engines, coz I googled, bang! (past tense for bing I guess!), and yahooed the crap out of the web and didn’t find any solution, until I saw a link to this in some pretty hidden place on Zeep website.

    Cheers,

  5. Leyla says:

    Thanks for the post!

    Just wondering if you had any idea on how to actually receive the messages that come in from the users? Zeep’s website does a bad job of explaining this stuff :\

    Thanks!!!

  6. […] https://aboutdev.wordpress.com/2009/02/09/zeep-mobile-sms-with-ads/Β  talks about sending messages to your subscribed users. I made some modifications to the code given there. Since this is originally AboutDev’s code, you’ll have to head over to that site and follow my modifications below. […]

  7. Adil Bukhari says:

    Thank you for this post!

    I referred to your code to give a complete C#/ASP.NET example for ZeepMobile – I hope you don’t mind!
    Here’s the post link: http://elektron9.wordpress.com/2010/03/23/zeepmobile-sending-and-receiving-messages-in-asp-net-c/

  8. markjoel60 says:

    Thanks for forging the trail! Good article

  9. CLN says:

    Hi,
    I just need your help, getting this problem in
    System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream(
    stream,false,new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate));
    sslStream.AuthenticateAsClient(uri.Host);

    “Error: No overload for ‘ValidateServerCertificate’ matches delegate ‘System.Net.Security.RemoteCertificateValidationCallback’

    Thank you in advance.

  10. aboutdev says:

    CLN, do you have the method ValidateServerCertificate in your code? If not you should add it from my code above. The error means that the delegate that is passed into the RemoteCertificateValidationCallback is not correct or could not be found.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: