Quicklinks
Authors: Dave Wade of Votident, Bart Jonkman of ActiveXperts Software B.V.
Content:
1. Background
2. Problem Statement
3. Goals of the new System
4. ActiveXperts SMS Messaging Server Solution
On April 19 2009, senate elections for a third of the seats in the Senate of Haiti were held. The senate elections were originally planned for March 2008, but were postponed.
Voters should vote for the renewal of 33% (ten of the thirty seats) in the Haitian Senate. This is according the Constitution of Haiti.
The government of Haiti is a semi-presidential (presidential-parliamentary) republic, where the president and the prime minister are both active participants in the day-to-day administration of the state.
The people in Haiti did not know where to vote (which location) for the senate elections. The Haitian CEP (Provisional Election Council) were looking for an information source that could tell each voter where to vote.
Goals of the new system:
With an SMS based solution:
The Votident organization is specialized in assisting election commissions in informing voter of the polling locations, updating addresses and registering new voters. ActiveXperts are developers of the ActiveXperts SMS Messaging Server software and experienced in implementing SMS projects, connecting to SMPP providers, etc.
Votident selected '200' and the central SMS number for Haitians to send their SMS to. Votident applied for this '200' number with Digicel (70% of the market in Haiti), Comcel (20%) and Clickatell (10%). A connection is established between ActiveXperts SMS Messaging Server and those three providers (either through a VPN or directly through the internet); therefore, 3 different SMPP channels were configured. The Haitian CEP (Provisional Election Council) handed a database with all 3,4 million potential voters in Haiti.
The SMS procedure is like this:
An 'success' reply sample:
Wap vote nan Ecole des Soeurs Bel Air Miragoane VILLE MIRAGOANE, NIPPE BV #9
An 'error' reply sample:
49834 Nimewo sa a pa bon. Se nimewo a selman pou antre.
The source code of the ActiveXperts SMS Messaging Server (written by Votident):
' // BEGIN CONSTANTS AND DECLARATIONS
CONST STR_DEBUGFILE = "C:\HaitiResponder.txt"
CONST STR_SQLCONNSTRING = "Provider=SQLNCLI10;Server=(local);Database=CEPSMS;Uid=sa;Pwd=******"
CONST B_LIVESEND = True 'Set to false to not actully send SMS messages but still log them.
Dim g_objMessageDB, g_objDebugger, g_objConstants
Dim g_strSmsResponseTemplate, g_strSmsFailResponse
' // END CONSTANTS AND DECLARATIONS
' // BEGIN INITIALIZATION
Set g_objConstants = CreateObject("Axsms-messaging-server.Constants")
Set g_objMessageDB = CreateObject("Axsms-messaging-server.MessageDB")
Set g_objDebugger = CreateObject("ActiveXperts.VbDebugger")
g_strSmsResponseTemplate = "Wap vote nan " & vbCRLF & "{0}" & vbCRLF & "{4}" & vbCRLF & "{1}, {2}" & vbCRLF & "BV #{3}"
g_strSmsFailResponse = "{0}" & vbCRLF & "Nimewo sa a pa bon." & vbCRLF & "Se nimewo a selman pou antre."
g_objDebugger.DebugFile = STR_DEBUGFILE
g_objDebugger.Enabled = False
' // END INITIALIZATION
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function ProcessMessage (numMessageID)
Dim objMessageIn, objMessageOut
g_objDebugger.WriteLine ">> ProcessMessage"
g_objMessageDB.Open
If( g_objMessageDB.LastError <> 0 ) Then
g_objDebugger.WriteLine "<< ProcessMessage, unable to open database"
Exit Function
End If
Set objMessageIn = g_objMessageDB.FindFirstMessage ( "ID = " & numMessageID )
If g_objMessageDB.LastError <> 0 Then
g_objMessageDB.Close
g_objDebugger.WriteLine "<< ProcessMessage, FindFirstMessage failed, error: [" & g_objMessageDB.LastError & "]"
Exit Function
End If
' Change Status to from Pending to Success. If you don't do it, the message will be processed by subsequent triggers (if defined) because message is still pending
objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS
g_objMessageDB.Save objMessageIn
g_objDebugger.WriteLine "Incoming message saved, result: [" & g_objMessageDB.LastError & "]"
ProcessQuery ( objMessageIn )
g_objMessageDB.Close
g_objDebugger.WriteLine "<< ProcessMessage"
End Function
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function ProcessQuery ( objMessageIn )
Dim objMessageOut, curCurrentPrice, strReplymessage, voterId
g_objDebugger.WriteLine ">> ProcessQuery"
If ( CleanVoterId( objMessageIn.Body, voterId ) = False ) Then
HandleBadIncomingMessage objMessageIn, ""
Else
HandleIncomingMessage objMessageIn, voterId
End If
g_objDebugger.WriteLine "<< ProcessQuery"
End Function
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function HandleBadIncomingMessage(objMessageIn, voterId)
g_objDebugger.WriteLine ">> ProcessQuery"
SendMessage objMessageIn.FromAddress, objMessageIn.ChannelID, objMessageIn.BodyFormat, Replace( g_strSmsFailResponse, "{0}", voterId )
g_objDebugger.WriteLine "<< ProcessQuery"
End Function
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function HandleIncomingMessage(objMessageIn, voterId)
Dim responseSms, FoundNumber
FoundNumber = GetResponseSms(voterId, responseSms)
If Not (FoundNumber) Then
HandleBadIncomingMessage objMessageIn, voterId
Exit Function
End If
g_objDebugger.WriteLine responseSms
SendMessage objMessageIn.FromAddress, objMessageIn.ChannelID, objMessageIn.BodyFormat, responseSms
End Function
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Sub SendMessage( strFromAddress, numChannelID, numBodyFormat, strBody )
Dim objMessageOut
g_objDebugger.WriteLine ">> Sending Message to: " & strFromAddress & " Body: " & strBody
If( B_LIVESEND ) Then
Set objMessageOut = g_objMessageDB.Create
If( g_objMessageDB.LastError = 0 ) Then
objMessageOut.Direction = g_objConstants.MESSAGEDIRECTION_OUT
objMessageOut.Type = g_objConstants.MESSAGETYPE_SMS
objMessageOut.Status = g_objConstants.MESSAGESTATUS_PENDING
objMessageOut.ToAddress = strFromAddress
objMessageOut.ChannelID = numChannelID
objMessageOut.BodyFormat= numBodyFormat
objMessageOut.Body = strBody
g_objMessageDB.Save objMessageOut
End If
End If
End Sub
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function GetResponseSms(voterId, ByRef responseSms)
g_objDebugger.WriteLine ">> GetResponseSms"
Dim objConn, RS, strQuery
responseSms = g_strSmsFailResponse
GetResponseSms = False
Set objConn = CreateObject("ADODB.Connection")
objConn.Open STR_SQLCONNSTRING
strQuery = "SELECT * FROM VOTERS WHERE ID_CITOYEN = '" & voterId & "'"
Set RS = objConn.Execute(strQuery)
If(RS.EOF = False) Then
'Yuck. VBS doesn't have good support for this.
responseSms = Replace(Replace(Replace(Replace(Replace(g_strSmsResponseTemplate, "{0}", RS("CV")), "{1}", RS("COMMUNE")), "{2}", RS("DEPARTEMENT")), "{3}", RS("BUREAUVOTE")), "{4}", RS("ADRESSE"))
GetResponseSms = True
Else
GetResponseSms = False
End If
objConn.Close
g_objDebugger.WriteLine "<< GetResponseSms"
End Function
' //////////////////////////////////////////////////////////////////////////////////////////////////////
Function CleanVoterId(messageBody, ByRef voterId)
Dim myRegExp
Set myRegExp = New RegExp
myRegExp.IgnoreCase = True
myRegExp.Global = True
myRegExp.Pattern = "[^\d]"
voterId = myRegExp.Replace( messageBody, "" )
If( Len(voterId) < 1 ) Then
CleanVoterId = False
Else
CleanVoterId = True
End If
End Function