Wednesday, April 11, 2007

RIM JDE: Using the Signing Tool on multiple computers

To use the signing tool from multiple computers simply copy the sigtool.csk and sigtool.db file from the bin directory of the JDE on computer 1 to the bin directory of the JDE on computer 2.

sigtool.csk has the private key
sigtool.db has the location of authorization server along with your registration PIN

Now when you run the Signature tool on the new computer if you see a screen saying not registered for any of the 3 types:RBB,RRT,RCR then simply open the sigtool.db file ad make sure it has 3 entries one for each type.

In my case the RBB had a different private key than RRT and RCR, so a simply opened sigtool.csk file in notepad and pasted the private key into it.

Now when I ran the Signature everything worked as desired. Hope this helps.

Thursday, March 22, 2007

.NET: Pushing Microsoft Excel, Access or SQL Server Data using Multiple Interfaces

Note: This article is written by me and was published in the BlackBerry Developers Journal in July 2005


This article will describe how to push data from Microsoft® Excel, Microsoft Access and Microsoft SQL Server to BlackBerry devices.

It builds on the article, .NET: A Simple C# Push Application and will demonstrate how to push Emergency Contact List (ECL) data to BlackBerry devices, and how to push ECL to BlackBerry devices by using three different interfaces depending on need.

  1. ECL Service Application

  2. This is like a Windows® Service, which performs a push at a regular interval to BlackBerry devices.
  3. ECL Command Line application

  4. A command line application that performs a push once to all BlackBerry devices.
  5. ECL GUI Application

  6. A Graphical User Interface (GUI) application that performs a push once to BlackBerry devices.

These interfaces depend on the ECL Logic Engine (ECLLogic.dll) to process the inputs and perform the push.

We will take all of the push logic described in the last article, put it in a Dynamic Link Library (DLL) file, and then use these interfaces to gather information from the user and pass it to the DLL so it can do the work for us.

Topics within this section include:

There are two push types that can be performed using the Browser application as detailed below.

Browser Channel Push

Browser channel push is used where the server encodes the contact data in an HTML page and pushes the page to the BlackBerry Browser. When the BlackBerry Browser receives a Channel Push, it stores the pushed content in its cache and adds an icon to the main ribbon that acts as a bookmark to that page. In this form, the program on the device is the BlackBerry Browser, so there is no ECL-specific code that needs to be installed on the device. Arrange to have a copy of the "ECLv2/Server/content" folder published as a web resource. You will need to make it possible for a BlackBerry device to fetch a URL such as "http://internal57.yourcompany.com:2303/ecl/content/ecl_unread_icon.gif" to obtain the data from "content\ecl_unread_icon.gif". You can set this property in the GUI and in Settings.config for the Service and Command Line Application.

For example.

[WebContextRoot]/ecl_unread_icon.gi.
[WebContextRoot]/ecl_read_icon.gi.
[WebContextRoot]/ecl.html --.

Client Catcher

Client catcher is used when the server encodes the contact data into a non-standard format then sends it to a custom application that must be installed on the user's BlackBerry device. When the catcher receives a pushed message, it stores the encoded data locally using the BlackBerry persistence framework. The user interface component of the BlackBerry device displays its locally stored copy of the contact list in a collapsible tree form.

Open the Application Loader file "ECLv2\Device\bin\ECLContactList.alx" with your BlackBerry Desktop Manager software and follow the procedure for installing the program on your USB connected device. Once installed, the catcher will run in the background. Alternatively, if using the simulator, open the workspace.

ECLv2\Device\src\Device\ECLContactList.jd.

... in the BlackBerry Java Development Environment (JDE) and press F5 to launch the BlackBerry device simulator. Make sure that the MDS Simulator is running too.

Customizing the Example

There are two kinds of customizations that are easily made to this example.
  1. Making it read a different spreadsheet/database format
  2. Changing how the list gets displayed on the BlackBerry device

It is important to understand how the server program reads data from the Excel workbook to make this demonstration work with different spreadsheet formats.

The server is "hard coded" to understand the arrangement of cells found in XYZ Company's spreadsheet/database table. It scans the worksheet from top to bottom, searching for rows that contain data in the first column but not in the second. Such rows are interpreted as group headings. Other rows are interpreted as people within the most recently started group. The data from all used cells in a person's row become the line items that make up the person's record when it is displayed on the device.

When the server program is processing a person's row and encounters a used cell, it applies the formatting rule for the appropriate column when generating that field's line item. Note that the spreadsheet heading row is ignored. Thus, as long as the new format is similar enough to the old, you can adapt the server to read a differently formatted spreadsheet by adjusting these properties.

The server software must be changed to read a drastically different format. All the logic for parsing spreadsheets is in "DataReader.cs". This component accesses the spreadsheet using the row/column interface provided by OLEDB. While the server issues SQL commands over OLEDB, it is not using a relational database paradigm; rather, it is using the scanning algorithm described earlier.

Another straightforward customization would be to modify how the contact list gets displayed on the device. This can be done in Settings.config file or GUI.

Open the following workspace in the BlackBerry JDE to alter the BlackBerry Handheld Software.

ECLv2\Device\srcECLContactList.jdw

After you have made the desired changes, you can run the result in the simulator. You must sign your compiled application to deploy on a real BlackBerry device because it uses RIM's persistence and networking APIs.

This demo includes a pre-signed build in "ECLv2\Device \bin\ECLContactList.cod" that can be installed without change.

You should be able to make changes you need to the look-and-feel of the device app by only minor edits to the code in "ECLv2\Device\src\ECLApplication.java".

"ECLv2\Device\src\PushedDataListener.java" is a fairly generic push listener, while "ECLv2\Device\src\DataStore.java" handles lower-level data management.

Note that there are fairly high degrees of coupling between "ECLv2\Device\src\DataStore.java" and "ECLv2\Server\src \CustomAppPusher.cs" since these classes jointly define the application's over-the-air transmission format.

Now that we have an understanding of the architecture, let's review the code.

The GUI Application has one class, PushDialog.cs. The main function is used to validate UI values and send them to ECLLogic.

The Command Line Application also has one class, CommandLine.cs. The main function is used to validate UI values and send them to ECLLogic.

The Windows Service Application has two classes.

  1. ECLService.c.
  2. ProjectInstaller.c.

The main function of ECLService is used to validate UI values then sends them to ECLLogic.

The ProjectInstaller.cs class handles the installation of a service.

These classes are used to get inputs and locations of data sources and pass them on to ECLLogic, which has all the Push Logic.

Now let us see how ECL Logic works.

Here is what happens:

Step 1

The interface class gets information from the user and then pass it to ECLLogic.cs. The ECLLogic.cs class has a struct in which the value is passed. The struct is called ECLConfiguration and can be seen below. This structure is used to send Connection information. It has twelve variables.

public struct ECLConfiguration
{
//File containing user information
//(Server Port Email/Pin)
public String recipientFile;

//Push Destination(Channel/Catcher)
public String PushTo;

//has a value 0 (Browser-Channel)
//or 1 (Browser-Channel-Delete)
public int PushType;

//This can be Access,Excel,MSSQL
public String ConnectionType;

//Database name,used in case of MS SQL
public String Database;

//File name(.xls or .mdb) or Server Name
//(used in MSSQL)
public String File_Server_Name;

//Worksheet Name(Used in Excel)
//or Table name (used in Access or MSSQL)
public String Sheet_Table_Name;

//The format in which data is displayed
//on the handheld
public String[] ColumnFormat;

//The location where the html file should
//stored after it has been formed
public String fileStoreLoc;

//The http:\\ URL where the read and
// unread icon files are
public String WebRoot;

//The name to be displayed as Channel Title
//on the handheld
public String ChannelName;

//The Source of the input(GUI/Console/Service)
public String Source;
}

Step 2

ECLLogic.cs receives the structure and then creates an instance of BrowserChannelPusher.cs or CustomAppPusher.cs. It then checks if the push type is Browser-Channel/ Browser-Channel Delete.

Pusher pusher = null;

if (config.PushTo == "Channel")
{
log.Info("Push To: Channel");

// Construct a pusher that sends to a
// browser channel.
pusher = new BrowserChannelPusher();
}
else if (config.PushTo == "Catcher")
{
log.Info("Push To: Custom Catcher");

// Construct a pusher that sends to a
// custom catcher.
pusher = new CustomAppPusher();
}

It then parses the recipient's list file to get user information and stores it in ArrayList.

ArrayList recipientEmails = getRecipients(config.recipientFile);

Step 3

If the push type is Browser-Channel then it calls DataReader.cs to access the data. While data is being accessed, it is also translated into HTML/comma delimited format by calling methods of the Pusher.cs class. All data sources have different connection strings whose configuration information is passed along with the ECLConfiguration struct from the interface classes.

//if Push Type is Browser-Channel
if(config.PushType==0)
{
// Open the data source from which we
// will read in contact data.
dataReader = new DataReader();

log.Info("Opening Data Source for retreiving data");
dataReader.openDB(config);

//Fetch the group names
log.Info("Getting list of group names");

System.Collections.ArrayList groupDescription = dataReader.GroupList(config);

// Assemble the data of all contacts (from all
// groups) that we will push to handhelds.
log.Info("Getting user contact information");

for (int j=0;j
{
System.String[] dataFields = dataReader.getContactData((System.String)
groupContactList[j],config);
pusher.addContact(dataFields);
}
}

// Log the message we just built
log.Info("Finished building the push message with contacts in " +
groupDescription.Count + " groups. " );
}

pusher.finishedConstruction(config.fileStoreLoc);

Step 4

After the data has been extracted and translated, all that is required is to push the data to the BlackBerry device. To accomplish this, loop the recipients list to send data.

// Push the message we just built to
// all recipients.
for (int i = 0; i <>
{
SenderInfo curRecipient = (SenderInfo) recipientEmails[i];

try
{
...
//Sends the message
success=pusher.sendToHandheld(curRecipient,config.WebRoot,
config.ChannelName,config.PushType);
...
}

The sendToHandheld method sets up the URL and the HTTP connection and
sends the data to the BlackBerry device.

Wednesday, March 21, 2007

.NET: A Simple C# Push Application

Note: This article is written by me and was published in the BlackBerry Developers Journal in July 2005

Push applications can be created using any development language that is able to initiate a network connection and perform an HTTP post. An HTTP post to the BlackBerry® Mobile Data Service (MDS) handles the delivery of pushed data to a BlackBerry device.

The post is made up of a standard HTTP request header, a few unique Browser Push headers and a stream of data.

Note: The web page does not have to be sent when performing a Browser Channel Delete Push Topics within this section include:
> Required HTTP request headers
* Required
* Optional
> How does the application work?
> Let's get started
> How the httpPush method performs the push

The following additional HTTP request headers are required for a browser push to take place:

Required

X-RIM-Push-Title
X-RIM-Push-Type

Optional

X-RIM-Push-Channel-ID
X-RIM-Push-UnRead-Icon-URL
X-RIM-Push-Read-Icon-URL

The "X-Rim-Push-Title" header contains the title that will appear either on the Home screen of the BlackBerry device for a Browser Channel Push, or in the subject of the message for a Browser Message Push.

The "X-RIM-Push-Type" header holds the value that represents the type of push being sent. Possible values are:
  • Browser-Channel
  • Browser-Message
  • Browser-Content
  • Browser-Channel-Delete

The "X- RIM-Push-Channel-ID" header contains the URL of the page to be pushed to the device. This is not required when performing a Browser Message or Browser Content push.

The "X-RIM-Push-UnRead-Icon-URL" and "X-RIM-Push- Read-Icon-URL" are optional headers that specify the URL of the icons to be used for a Browser Channel Push. If not specified then the default Browser Channel Push icons are used. These two headers are not required for Browser Message, Browser Content or Browser Channel Delete Push and may be omitted

This article will show how to create an application to push a URL to one or more BlackBerry device users. For further information, please refer to "Push Me! Pushing web content to BlackBerry" in Volume 2, Issue 1 of the BlackBerry Developer Journal.

How does the application work?

When you run the application you will see the screen below.

Figure 1

Figure 1

Click the "Open" button to select a file that contains a list of BlackBerry device users with their BlackBerry Enterprise Server host, port and email/PIN. The following line shows the format of a "User Information File":

localhost 8080 2100000A

In this example, localhost is the name of the server that push is being sent to, port 8080 is the web server listen port on that server, and the PIN is set to 2100000A.

Note: The "User Information File" must be saved with an extension of ".txt"

Select the push type to continue and then specify the URL and the push name. If you want a read and unread icon to be published, provide URLs. Otherwise, leave the settings blank.

Note: Run the MDS Simulator before the BlackBerry device simulator to see the following results.

When the Send Push button is pushed, you should see the following icon in your simulator screen.

RIM Homepage

Let's get started
Figure 2

Download and unzip BlackBerryBulkPush.zip, and then open BlackBerryBulkPush.sln. This is a solution file that includes the setup project and the source project. When you open this project you will see the screen in Figure 3.

The solution explorer shows six files in the BlackBerryBulkPush Project. The files have the following functions:

App.config Used for configuration of logging framework log4net
App.ico Icon file
AssemblyInfo.cs File generated by VS .Net
HttpPushWorker.cs Performs the push operation
PushDialog.cs The UI for the Bulk Push
README.doc Installation instructions and known issues as of a certain date

Figure 2

Figure 3

The two relevant classes are PushDialog.cs and HttpPushWorker.cs. When the Send Push button is pressed, it invokes the button1_Click event in PushDialog.cs. Let’s review the button1_Click code to see what happens:

private void button1_Click(object sender, System.EventArgs e)
{
int pos,start;
string BESAddress,BESPort,Email,url;
string fDelimiter= " ";

//verifying information is filled correctly
if(verifyFields())
{
url="http://"+PushURLTextBox.Text;
} else {
this.PushStatusBar.Text = "Missing Required Fields";
return;
}

//checking for correct file (.txt extension)
if((txtFileName.Text).Substring((txtFileName.Text).IndexOf(".",0)+1,3) != "txt")
{
MessageBox.Show("Please enter a file with extension .txt");
return;
}

//checking if file exists
if (!File.Exists(txtFileName.Text))
{
MessageBox.Show(this,"Incorrect file name");
return ;
}

//verifying url
PushStatusBar.Text = "Requesting Page Data";
HttpPushWorker pusher = new HttpPushWorker(ref PushStatusBar,ref url);

if ( url == "Wrong" )
{
PushStatusBar.Text = "Push Failed, bad URL";
return;
}

// create reader & open file
TextReader sr = new StreamReader(txtFileName.Text);

//reading contents into string variable
string fContent = sr.ReadLine();

/*looping thrugh the reader and parsing the BES address,port and email from the file*/
while (fContent != null)
{
pos=0;
start=0;
try
{
//looking for " "
pos=fContent.IndexOf(fDelimiter,start);

//pushing pos and start variable to parse Address
BESAddress=fContent.Substring(start,pos);

//setting start position for port
start=pos+1;

//looking for " "
pos=fContent.IndexOf(fDelimiter,start);

//using pos and start variable to parse Port
BESPort=fContent.Substring(start,pos-start);

//setting start
start=pos+1;

//using length and start to parse email
Email=fContent.Substring(start,fContent.Length-start);

//logging the parsed infomation
log.Info("Sending: " + BESAddress + " " + BESPort + " " + Email);

//Verifying the parsed information
if (verifyFile(BESAddress,BESPort,Email))
{
//calling the push method to perform push
pusher.httpPush(BESAddress,BESPort,
PushTypeBox.SelectedIndex,PushNameTextBox.Text,
"http://"+PushURLTextBox.Text,"http://"+ReadIconURLTextBox.Text,
"http://"+UnreadIconURLTextBox.Text, Email);
}
else
{
MessageBox.Show("Error:The file does not have proper formatting");
return;
}

//reading line
fContent= sr.ReadLine();
}
catch(Exception t)
{
log.Info("Exception: "+ t.Message,t);
sr.Close();
return;
}
}
//closing stream reader
sr.Close();
}

The method above declares variables and performs field, file, and URL verification and validation. It then passes the Status Bar and the URL by reference to an instance of HttpPushWorker class. A text reader is then created to read through the user file.

The httpPush method in the HttpPushWorker class is then called to push the web page to the user. Each user information is read and then the URL is pushed. Once all lines have been read from the user file the reader will close the file.

How the httpPush method performs the push

The httpPush method within the HttpPushWorker.cs class first reads in the source data and then adds it to the push connection. The method will also add all necessary HTTP headers that the BlackBerry Browser uses to identify this connection as an HTTP push.

Parameters Description
BESAddress Address (or IP) of the BlackBerry Enterprise Server/BlackBerry Mobile Data Service
BESWebserverListenPort Port the BlackBerry Mobile Data Service listens on for incoming connections
typeIndex Index of the push type (PUSH_TYPES)
pushTitle Title to use for the push
url URL of the source page
readIconURL URL of the read icon to use (for channel push)
unreadIconURL URL of the unread icon to use (for channel push)
pushPin PIN or Email address of the BlackBerry device user to push to
public void httpPush(string BESAddress, string BESWebserverListenPort, int typeIndex,
string pushTitle, string url, string readIconURL, string unreadIconURL, string pushPin)
{
string pushPort = "7874";
string pushType = PUSH_TYPES[typeIndex];
status.Text = "Sending Push";

//Create the push URL for MDS

string httpURL = "http://"+BESAddress+":"+BESWebserverListenPort
+ "/push?DESTINATION=" + pushPin+"&PORT=" + pushPort + "&REQUESTURI=/";

//make the connection
//we'll put this whole thing in a try/catch block for some basic error handling.
try
{
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(httpURL);
HttpWReq.Method = ("POST");

//add the headers nessecary for the push
HttpWReq.Headers.Add("Content-Location",url);
HttpWReq.Headers.Add("X-RIM-Push-Title", pushTitle);
HttpWReq.Headers.Add("X-RIM-Push-Type",pushType);

if (pushType.Equals("Browser-Channel") || pushType.Equals("Browser-Channel-Delete"))
{
HttpWReq.Headers.Add("X-RIM-Push-Channel-ID", url);
if (pushType.Equals("Browser-Channel"))
{
HttpWReq.Headers.Add("X-RIM-Push-UnRead-Icon-URL",unreadIconURL);
HttpWReq.Headers.Add("X-RIM-Push-Read-Icon-URL", readIconURL);
}
}

//add some of the headers from the source page
int headerCount = headers.Count;


//add some of the headers from the source page
int headerCount = headers.Count;

for (int i = 0; i
{
Console.Out.WriteLine("Adding Header = "+headers.GetKey(i));
if (headers.GetKey(i).ToLower().Equals("content-type"))
{
HttpWReq.ContentType = headers.Get(i);
}
}

HttpWReq.ContentLength = data.Length;

//Getting Request stream to write data to it
Stream requestStream = HttpWReq.GetRequestStream();

//Write the data from the source
requestStream.Write(data,0,data.Length);

//get the response (this should be HTTP 200)
HttpWebResponse HttpWRes = (HttpWebResponse)HttpWReq.GetResponse();

//Update status on the Status Bar wich Is passed by reference from PushDialog.cs
if (HttpWRes.StatusCode == HttpStatusCode.OK)
{
status.Text = "Pushed";
} else {
status.Text = "Push Failed, bad response";
log.Info("Failed to Push");
}

//Close the streams
status.Text = "Closing Streams";
requestStream.Close();
HttpWRes.Close();
status.Text = "Success with "+ timesFailed + " Failures";
}
catch(System.Exception e)
{
log.Error("Push Failed "+ e.Message,e);
++timesFailed;
status.Text = "Push Failed, could not send";
}
}

In the method above, the variable PUSH_TYPES is a String array with the following structure

public static string[] PUSH_TYPES = new string[]{
"Browser-Channel","Browser-Cache",
"Browser-Message","Browser-Channel-Delete"
};

PUSH_TYPES is declared in the HttpPushWorker class. After variable declaration, a URL is created that allows the application to perform the HTTP Post necessary to push the page to the BlackBerry Mobile Data Service and the BlackBerry device. Once created, the connection to MDS is established, specific headers are added to the request.

A request stream is then obtained to write source data (web page) to the destination. When the data has been written to the stream, the response from the HTTP request is checked for status 200. The response is used to inform the user about the status of the push. The status is displayed on the status bar in PushDialog.cs.

Tuesday, March 20, 2007

.NET : Building Mobile Web Forms for BlackBerry

Note: This article is written by me and was published in the BlackBerry Developers Journal in July 2005

In this article I will show how to build a simple travel request form using ASP .NET that sends form data to specific users as email.
Let's get started...

Note: VS 2005 does not have Mobile Forms Template. You can download it here. Thanks Omar!!

Open Microsoft Visual Studio® .NET and start a new project of type "ASP .NET Mobile Application". In Form1.aspx, create an interface as shown below.
Double click on "Submit" and then enter in the following code:

using System.Web.Mail;
private void Command1_Click(object sender, System.EventArgs e)
{
//perform validation
if(txtMailTo.Text=="" || txtFrom.Text=="")
{
Response.Write("Please fill in to and from fields");
}
//If the code is validated then take all
//the input values and form an HTML message
else
{
MailMessage m=new MailMessage();

//Get input values from the form
m.To= txtMailTo.Text;
m.From=txtFrom.Text;
m.Subject="Travel Request";
m.BodyFormat=MailFormat.Html;
m.Body= "Name : "+TextBox1.Text +""+
"Department : "+ TextBox2.Text +""+
"Cost Center and GL : " + TextBox3.Text +""+
"Manager : "+ Textbox4.Text +""+
"Name of VP to Authorize : " + Textbox5.Text +""+
"Destination : "+ Textbox6.Text +""+
"Date and Time of Departure : " + Textbox7.Text +""+
"Additional remarks :"+ Textbox18.Text ;

//Send the message
System.Web.Mail.SmtpMail.Send(m);

//Redirect the user to another page saying
// message was sent successfully
this.RedirectToMobilePage("MsgSend.aspx");
}
}
Post the page to your internal web server, access it from your BlackBerry device, enter some test data and then press the submit button to send an email to the user in HTML format. This application can also be extended to send form data to a database instead of an email.