v1.2.3 released

April 1st, 2011 § 4 comments § permalink

I just released v1.2.3 of Corporate Addressbook to the Android Market.

Features and fixes include:

  • Support for Zimbra (Issue #47)
    • Zimbra did not like the query string that was sent from the app, and threw and error 500 on each search request received. Turns out that it required that the optional range element be included in every request. Thanks Stephen and Martin for helping debug this issue.

  • Error Code 0 (Issue #49)
    • Looks like a lot of people were seeing an error code 0 returned when they were trying to log in. Debugging with a few folks led to two discoveries
      1. Spaces in username: I had failed to URL encode the URL that is generated by concatenating the server name with the username. As a result of this any spaces in the username caused HttpOptions to barf.
      2. Any exceptions thrown during the connection process were being handled, but the actual error string was not propagated up to the UI.  Added some code to make the actual error string more user friendly. Hopefully this should help in getting to the bottom of connection issues.

  • Login screen does not scroll in landscape mode (Issue #40)
    • The login screen worked fine in portrait but was completely broken in the landscape mode. Dale picked up this issue and added a Scroll View to the UI. This should allow users to scroll to the Login button.

Carlsbad Marathon – In retrospect

February 25th, 2011 § 0 comments § permalink

Now that the dust from my marathon has settled, and my sores have healed :), I thought it is time to retrospect on the experience, and share some tips.

Training Schedule

I think it is important to have a training schedule, and especially one that you can stick with. I found Hal Higdon’s Marathon training guide online, and decided to use it to train for my marathon. This worked quite well for me. I setup a Google calendar with a reminder for all my runs, and synced this with my phone. This kept me motivated and ensured that I got the training I needed. A big thumbs up for this great online resource.

Footwear

Choosing the right footwear is crucial, and you really need to find something that works for you and protects you from  injuries. When I first started running My Vibram KSOrelatively long distances (~ 6 miles) in 2009, I used to run with regular running shoes. However over a period of time, I started experiencing knee pain which unfortunately seems to plague most of the runners out there. I started looking around for solutions, and this was when I heard aboutVibram FiveFingers. I liked what I read and decided to buy myself a pair of KSO’s. I will be very honest, the first few days of running with my Vibram’s were painful. My calves hurt like hell, and the distance I could run without being out of breath or in pain went down considerably. But my knee pain became a thing of the past, and I only had sweet pain in my calves. So I decided to stick to my newly acquired Vibram’s and have been very happy with my decision ever since. Trust me there are plenty of nay-sayers out there, and Vibram’s  might just not be for you, but they worked really well for me. I now plan to pick up a pair of Bikila’s which are supposedly designed for running.

Clothing

Once you start hitting the 13+ mile mark, clothing becomes a very important consideration, since chafing can make your run extremely painful and uncomfortable. For shorts I would highly recommend  Nike Dri-Fit shorts that come with briefs built in. For shirts, I  just picked something that kept the sweat away (REI has a really good selection), leaving me dry and comfortable. Besides this for all other chafing issues, I picked up some anti-friction cream from Sports Chalet and that did the trick.

Accessories

Beyond this, I found it quite helpful to pick up a bottle holder, that I could clip to my wait. This allowed me to carry some water, and also a few food supplies (energy gels, energy bars) for the long run. Also I bought a spare battery and a armband for my Nexus One. This way I could track my progress, and map my runs. If you have an Android phone, I would highly recommend CardioTrainer. Great app, awesome functionality, and it does not kill the battery.

Carlsbad Marathon – Statistics, Videos and Pictures

February 23rd, 2011 § 1 comment § permalink

I successfully ran the 2011 Carlsbad Marathon in  4:08:58.  I thought I should share some statistics, pictures and videos from the event.

I don’t think I would have been able to make it without the support of my loving wife. She put up with my 4 day a week running schedule, each of which sometimes lasted as long as 4 hours (bye bye weekend). She also pushed me to train, when I was too lazy and wanted to call it quits, egging me along all the time.

Pictures


Statistics

Here are the statistics of my marathon run (Source)

Race Results
Overall452 out of 1173
Men314 out of 683
Men (30-34)62 out of 107
Age/Grade50.18%
Place: 691
Finish4:08:58
Pace: 9:30
Tag Time4:08:58
Gun Time4:09:21
Split Times
9.32 miles (15 km)1:23:31
Pace: 8:58
13.67 miles (22 km)2:01:59
Pace: 8:55
18.00 miles (28.97 km)2:41:18
Pace: 8:58
19.8 miles (31.87 km)2:58:58
Pace: 9:03

Video at the finish line

ActiveSync Primer continued – The PROVISION command

February 3rd, 2011 § 1 comment § permalink

The PROVISION command and response is used by Exchange servers to communicate security policy settings to client devices.  If a security policy has been setup for an Exchange server, Exchange will not process any requests received from a client, until the policy settings are requested and acknowledged by the client. Please see the ActiveSync Provisioning Protocol Specification for more information about this command.

Depending upon the version of the Exchange server one of the following error messages are returned when a client issues a request before accepting the security policies.

  • HTTP/1.1 449 : Retry after sending a PROVISION command
  • HTTP/1.1 200 with a global status code in the body of the response of 142 (see example here).

A lot of this is repeated from the ActiveSync provisioning protocol documentation. However there are a few gotchas here, so I think it might be better to step through it.

Step 1: Client requests security policy from the server

Header

// Send a POST request to the mail server. Append
// the string “Microsoft-Server-ActiveSync” to the URL, and add the
// the following query strings as parameters to the URL as shown below
// username - Username used to log into the server.
// deviceId: DeviceId for the device (not validated by server)
// deviceType: Type of device (not validated by server)
// cmd: The actual command being sent across (Provision in this case)

POST https://mail.example.com/Microsoft-Server-ActiveSync?User=username&DeviceId=123412341234&DeviceType=Android&Cmd=Provision HTTP/1.1

// Set the user-agent
User-Agent: Android

// Authorization: This is the text Basic followed by a
// base64 encode of the string DOMAIN\USERNAME:PASSWORD.
// Replace with appropriate values.
Authorization: Basic RE9NQUlOXFVTRVJOQU1FOlBBU1NXT1JE

// Set the content-length to the length of the WBXML being sent (more on this in a bit)
Content-Length: FIXME

// Indicate to the Exchange server that we are sending
// WBXML encoded content.
Content-Type: application/vnd.ms-sync.wbxml

// Identifies the protocol version the client (we) support
// NOTE: This cannot be higher than the highest ActiveSync protocol
// version supported by the server. See my Options primer
// for details.
// Also I would recommend setting this to 12.1, because some Exchange
// 2010 requires servers (v14.1) require 14.1 clients to send several
// optional fields (yep you read that right). Setting this to 12.1
// makes your life a wee bit easier.

MS-ASProtocolVersion: 12.1

// English language
Accept-Language: en-US

// Hostname the request is being sent to
Host: mail.example.com

// Set the PolicyKey to zero indicating to the server
// That you do not currently have a policy key
X-MS-PolicyKey: 0

Body

// Send the following XML string to the server.
// Note that the XML below has to be encoded
// into WBXML before sending it across to the
// Exchange server. More on this in a bit.
// The policyType should be set to
// MS-EAS-Provisioning-WBXML if the activeSync version greater
/ than or equal to 12.0, MS-WAP-Provisioning-XML otherwise

<?xml version="1.0" encoding="utf-8"?>
<Provision xmlns="Provision:">
	<Policies>
		<Policy>
			<!-- If ActiveSync Version >= 12.0 -->
			<PolicyType>MS-EAS-Provisioning-WBXML</PolicyType>
			<!-- If ActiveSync Version < 12.0 -->
			<PolicyType>MS-WAP-Provisioning-XML</PolicyType>
		</Policy>
	</Policies>
</Provision>

Now the XML in the body above has to be encoded into WBXML, before it can be sent across to the server. This is true for all ActiveSync commands that have a body. I wrote a Java implementation of a WBXML encoder and decoder for my app, and you can find the source code here. The source code is based on a WBXML parser I found in the k9mail. I modified the source to add support for International languages.

Step 2: Server responds to client request with security policy and temporary policyKey

Once the request above is sent to the server, you should get a response that looks somewhat like this. Again the XML returned from the server is encoded in WBXML. It is the client’s responsibility to decode this WBXML and make sense of it.

HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 1069
Content-Type: application/vnd.ms-sync.wbxml
Server: Microsoft-IIS/7.5
MS-Server-ActiveSync: 8.3
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Cache-Control: private
Date: Mon, 01 Feb 2011 21:14:17 GMT

<?xml version="1.0" encoding="utf-8"?>
<Provision xmlns="Provision">
<Status>1</Status>
<Policies>
<Policy>
<PolicyType>MS-EAS-Provisioning-WBXML</PolicyType>
<Status>1</Status>
<PolicyKey>2152355410</PolicyKey>
<Data>
	<EASProvisionDoc>
		<DevicePasswordEnabled>0</DevicePasswordEnabled>
		<AlphanumericDevicePasswordRequired>0</AlphanumericDevicePasswordRequired>
		<PasswordRecoveryEnabled>0</PasswordRecoveryEnabled>
		<DeviceEncryptionEnabled>0</DeviceEncryptionEnabled>
		<AttachmentsEnabled>1</AttachmentsEnabled>
		<MinDevicePasswordLength/>
		<MaxInactivityTimeDeviceLock/>
		<MaxDevicePasswordFailedAttempts/>
		<MaxAttachmentSize/>
		<AllowSimpleDevicePassword>0</AllowSimpleDevicePassword>
		<DevicePasswordExpiration/>
		<DevicePasswordHistory>0</DevicePasswordHistory>
		<AllowStorageCard>1</AllowStorageCard>
		<AllowCamera>1</AllowCamera>
		<RequireDeviceEncryption>0</RequireDeviceEncryption>
		<AllowUnsignedApplications>1</AllowUnsignedApplications>
		<AllowUnsignedInstallationPackages>1</AllowUnsignedInstallationPackages>
		<MinDevicePasswordComplexCharacters>3</MinDevicePasswordComplexCharacters>
		<AllowWiFi>1</AllowWiFi>
		<AllowTextMessaging>1</AllowTextMessaging>
		<AllowPOPIMAPEmail>1</AllowPOPIMAPEmail>
		<AllowBluetooth>2</AllowBluetooth>
		<AllowIrDA>1</AllowIrDA>
		<RequireManualSyncWhenRoaming>1</RequireManualSyncWhenRoaming>
		<AllowDesktopSync>1</AllowDesktopSync>
		<MaxCalendarAgeFilter>0</MaxCalendarAgeFilter>
		<AllowHTMLEmail>1</AllowHTMLEmail>
		<MaxEmailAgeFilter>0</MaxEmailAgeFilter>
		<MaxEmailBodyTruncationSize>-1</MaxEmailBodyTruncationSize>
		<MaxEmailHTMLBodyTruncationSize>-1</MaxEmailHTMLBodyTruncationSize>
		<RequireSignedSMIMEMessages>0</RequireSignedSMIMEMessages>
		<RequireEncryptedSMIMEMessages>0</RequireEncryptedSMIMEMessages>
		<RequireSignedSMIMEAlgorithm>0</RequireSignedSMIMEAlgorithm>
		<RequireEncryptionSMIMEAlgorithm>0</RequireEncryptionSMIMEAlgorithm>
		<AllowSMIMEEncryptionAlgorithmNegotiation>2</AllowSMIMEEncryptionAlgorithmNegotiation>
		<AllowSMIMESoftCerts>1</AllowSMIMESoftCerts>
		<AllowBrowser>1</AllowBrowser>
		<AllowConsumerEmail>1</AllowConsumerEmail>
		<AllowRemoteDesktop>1</AllowRemoteDesktop>
		<AllowInternetSharing>1</AllowInternetSharing>
		<UnapprovedInROMApplicationList/>
		<ApprovedApplicationList/>
	</EASProvisionDoc>
</Data>
</Policy>
</Policies>
</Provision>

The 200 response code indicates a success. The XML returned from the server contains the security policy that the server would like the client to implement. Once the client receives this security policy, it needs to implement the security policy indicated in the XML, and then acknowledge receipt of the security policy. Note that the policyKey (2152355410) returned by the server in the response is temporary and needs to be sent to the server in Step 3 (acknowledgement).

Step 3: Client acknowledges receipt and application of security policy

The client should now acknowledge the security policy and its application by using the temporary policyKey obtained in Step 2.

POST https://mail.example.com/Microsoft-Server-ActiveSync?User=username&DeviceId=123412341234&DeviceType=Android&Cmd=Provision HTTP/1.1
User-Agent: Android
Authorization: Basic RE9NQUlOXFVTRVJOQU1FOlBBU1NXT1JE
Content-Length: FIXME
Content-Type: application/vnd.ms-sync.wbxml
MS-ASProtocolVersion: 12.1
Accept-Language: en-US
Host: mail.example.com
X-MS-PolicyKey: 2152355410

<?xml version="1.0" encoding="utf-8"?>
<Provision xmlns="Provision:">
  <Policies>
    <Policy>
      <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType>
      <PolicyKey>2152355410</PolicyKey>
      <Status>1</Status>
    </Policy>
  </Policies>
</Provision>


Step 4: Server responds with final policyKey

At this point the server will respond with the “final” policyKey which the client then uses in the X-MS-PolicyKey header of all successive command requests to the server.

HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 1069
Content-Type: application/vnd.ms-sync.wbxml
Server: Microsoft-IIS/7.5
MS-Server-ActiveSync: 8.3
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Cache-Control: private
Date: Mon, 01 Feb 2011 21:15:17 GMT

<?xml version="1.0" encoding="utf-8"?>
<Provision xmlns="Provision:">
  <Status>1</Status>
    <Policies>
       <Policy>
           <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType>
           <Status>1</Status>
           <PolicyKey>12432432244</PolicyKey>
       </Policy>
     </Policies>
</Provision>

A word of caution here. I have seen cases where a server processes a few client requests that contain the final policyKey obtained using the method above, and then start sending down a 449 or a 142 error code. This implies that the client needs to acknowledge the policy settings again. So make sure you always check for 142 and 449 error codes even if you have accepted the policy settings once and received a final policyKey.

Use a smartphone and like your apps? You just lost your privacy

December 20th, 2010 § 1 comment § permalink

Interesting read

The Journal‘s report lays bare much of what we already suspected, or outright knew but didn’t bother thinking about: iOS and Android apps are having a field day with your personal info. More than half of the 101 popular apps they tested sent your UDID to companies without your awareness or consent. Nearly as many sent your location, and a handful even sent along demographic info and other personal details to advertisers.

It’s a small sample size given the hundreds of thousands of apps out there, but it’s hard to imagine that the most prominent names just happen to be the most aberrant. And the list of worst offenders also reads like a roll-call of must haves: Pandora. Angry Birds. Netflix. Shazam. Et tu, Yelp?

Also something very interesting

iOS apps shared more data than Android apps, on the whole—somewhat surprising given the rigidity of the App Store approval process compared to Android’s looser environment. And there’s really nothing you can do to stop it.

So just because your App store is curated doesn’t mean squat. Companies get a free reign on your data anyway.

How come Gruber never links to articles like this, but loves linking to articles like this?

An Activesync Primer – The Options request

December 6th, 2010 § 4 comments § permalink

Now that my app is out in the market (finally), I think it is time to write a brief how-to on ActiveSync and how I managed to get things working.

First off, I would like to acknowledge the help and support from the following individuals / websites, without  whom this app would not been possible

Ok lets get started.

The Activesync OPTIONS Command

This is the first command that you want to send to an ActiveSync server. If the message is correctly formatted, the server responds with with a list of commands supported, and also the ActiveSync version that is supported. Here is a sample request (RAW view from Fiddler). Please note that the text in bold will need to be modified, and actual values will need to be inserted. See comments prefixed by // for a better description of each field.

[EDIT 01/20/2011] Turns out if you are connecting to Google Apps (that runs on Linux) or an Exchange server that is protected by a reverse proxy, case matters. so the Activesync text below should be ActiveSync (note the camelcase)
// Send an Option request to the mail server. Append the
// following location to the URL Microsoft-Server-ActiveSsync
// and add the username used to log into the server.
OPTIONS https:/ /mail.example.com/Microsoft-Server-ActiveSsync?User=username HTTP/1.1

// Set this to anything. Since I wrote an Android app,
// I set this to Android
User-Agent: Android

// This is the text Basic followed by a
// base64 encode of the string DOMAIN\USERNAME:PASSWORD.
// Replace with appropriate values.
Authorization: Basic RE9NQUlOXFVTRVJOQU1FOlBBU1NXT1JE

[EDIT 01/20/2011] Exchange server 2010 does not like it if you send any additional headers. The only required headers are the auth and the user-agent. Hence none of the headers below are required for the OPTIONS request
// Since this is an Options request, there is no content
// just the headers. Hence this is set to zero
Content-Length: 0

// Indicate to the Exchange server that we are sending
// WBXML encoded content.
// Right now since is not really applicable.
Content-Type: application/vnd.ms-sync.wbxml

// Identifies the protocol version the client (we) support
MS-ASProtocolVersion: 12.1

// English language
Accept-Language: en-US

// Hostname the request is being sent to
Host: mail.example.com

If all goes well, you should get a response that looks somewhat like this

HTTP/1.1 200 OK
Cache-Control: private
Allow: OPTIONS,POST
Content-Length: 0
Server: Microsoft-IIS/7.5
MS-Server-ActiveSync: 8.3
MS-ASProtocolVersions: 1.0,2.0,2.1,2.5,12.0,12.1
MS-ASProtocolCommands: Sync, SendMail, SmartForward, SmartReply, GetAttachment, GetHierarchy, CreateCollection, DeleteCollection, MoveCollection, FolderSync, FolderCreate, FolderDelete, FolderUpdate, MoveItems, GetItemEstimate, MeetingResponse, Search, Settings, Ping, ItemOperations, Provision, ResolveRecipients, ValidateCert
Public: OPTIONS,POST
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Mon, 06 Dec 2010 21:14:17 GMT

The 200 response code indicates a success. The MS-ASProtocolVersions field indicates the version of the Activesync Protocol that is supported by the server. The MS-ASProtocolCommands field indicates what Activesync commands are supported by the server.

I will keep updating my blog with more information on how to use Activesync to query the GAL. Stay tuned.

Gingerbread (Android 2.3) is out

December 6th, 2010 § 3 comments § permalink

Now that Gingerbread is out, will it make my app obsolete? Only time will tell.

Corporate Addressbook on the AppBrain hot apps list

November 29th, 2010 § 2 comments § permalink

My app is now one of the top 10 hottest apps on Appbrain. Woot !!

Appbrain top 10 hot apps

Corporate Addressbook – now available on the Android market

November 16th, 2010 § 20 comments § permalink

My first Android app (Corporate Addressbook) is now available on the Android market.

I wrote this app since my Nexus One lacks a feature that I really needed – a true GAL lookup. The Global Address List (GAL) lookup currently available in vanilla Android (Froyo running on my Nexus One) is quite limited in functionality. It only looks up email addresses and does not return anything more. This is quite frustrating when you are trying to look up the address book for the contact information of a colleague. The only other option was to buy Touchdown. Touchdown is a great app, however it does much more than GAL lookups. It also fetches email and does a bunch of other things that are now included in Froyo. Hence I thought it was better to write this application to meet my requirement.

This application looks up the GAL and returns ALL data that is available on the Exchange server for the query. The app uses the ActiveSync protocol to communicate with the Exchange server, and supports both Exchange 2003 and 2007.

The source for this app is available on Google Code, and is available via the Apache 2.0 license.

Download it while it is hot :)

Appbrain
Android Market

Please do let me know if you come across and bugs / issues or if you have any comments.

Exception #11 on Amazon MP3 Android App

October 5th, 2010 § 1 comment § permalink

If you see this error when using the Amazon MP3 Android app to download songs, don’t bother calling Amazon Customer Care (like I did). I was told that it was a problem with my ISP (Yeah, you heard me right). Any way you will see this error if you do not 1-Click ordering enabled on your Amazon account. Follow the instructions here to turn on -Click ordering, and you should be good to go.