logo

Passing arguments to a LotusScript agent

One of the topics that seems to keep popping up on the Notes.net Café is passing arguments to agents on the web. Half the postings asking "can you do it?"; the other half asking "how do you do it?". In answer to the first half: yes you can. In answer to the other half: read on...

Passing paramaters to an agent works in exactly the same way as passing parameters to a form or a page: we do it using the Query String portion of the URL. A typical URL looking something like this:

../db.nsf/url?OpenAgent&Name=Jake&Age=26&Country=UK

The code required in the agent to strip these values out of the URL can often become quite complicated and often required hard coding the name of the value that we want to look for. The following code can be re-used in any agent, and simply place all the arguments and their corresponding values in to a nice list. We can then look in this list and retrieve a particular value simply by supplying its name.

The agent starts with the standard declarations:

Dim s As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Set db = s.CurrentDatabase
Set doc = s.DocumentContext
Followed by declaring the list variable that will hold all the arguments and their values:
Dim AgentArgs List As String
and a call to the subroutine that does all the work (code appears further down the page):
Call ExplodeQueryString (doc.Query_String_Decoded(0)
, AgentArgs)
This list would normally be used to let the agent go and retrieve the required information, but, for the sake of a demo, lets loop through all the parameters and send their key/value pairs back to the browser:
Forall Args In AgentArgs
Print "Parameter Key: " + Listtag(Args) + "<br />"
Print "Parameter Value: " + Args + "<p />"
End Forall
This method of looping through ALL the arguments may not be necessary if you already know the name of the parameter's key. For example, if a key had the name "Country", you could get to its value like this:
Print "Country Code: " + AgentArgs("country")
The ExplodeQueryString sub-routine:
Private Sub ExplodeQueryString (QueryString As String,
AgentArgs List As String)
Dim Args As String
Args = RightStr(QueryString, "OpenAgent&")

Dim ArgsList As Variant
ArgsList = Evaluate ({@Explode("} & Args & {"; "&")})

Dim ArgKey As String
Dim ArgValue As String

Forall Arg In ArgsList
ArgKey = LeftStr(Arg, "=")
ArgValue = RightStr(Arg, "=")
AgentArgs(ArgKey) = ArgValue
End Forall
End Sub
In order to reference a member of the list explicitly, like we did above, it is wise to check that it exists first. If you try to access a list item that does not exist the script will error. Use the IsElement method to help avoid errors:
if IsElement( AgentArgs ("ID") ) then
print "Your ID number is " + AgentArgs ("ID")
else
print "There is an error in the URL that was used."
end if
Overall, not a particularly useful example, I know, but I'll leave it to you as to how you wish to implement it.....



The LeftStr and RightStr functions
Function LeftStr(OrigStr, LeftOf ) As String
Dim Pos As Integer
Dim OrigStrLen As Integer
Pos = Instr( Lcase(OrigStr), Lcase(LeftOf) )
OrigStrLen = Len(OrigStr)
If pos>0 Then
LeftStr = Left( OrigStr, (Pos-1))
Else
LeftStr = OrigStr
End If
End Function

Function RightStr(OrigStr, RightOf ) As String
Dim Pos As Integer
Dim OrigStrLen As Integer
Dim RightOfLen As Integer
Pos = Instr( Lcase(OrigStr), Lcase(RightOf) )
OrigStrLen = Len(OrigStr)
RightOfLen = Len(RightOf)
If Pos>0 Then
RightStr = Right( OrigStr, OrigStrLen -
(RightOfLen+Pos-1))
Else
RightStr = OrigStr
End If
End Function

Feedback

  1. Another way of passing arguments to an agent

    I found another effective method of passing values to an agent which I used to get around the limitation of the Query_String CGI variable.

    First you must create a form tag on your current form.

    <FORM NAME="formsubmit" METHOD="post" ACTION="<agentname>?openagent"> <input type="hidden" name="selecteddocs" value="<Computed Value>"> </FORM>

    Next create input tags for all fields you need to send to the agent inbetween the form tags.

    From your action button on the main form, submit this form which causes the agent associated with the form action to run.

    In the agent you will have to use the functions below to get the values of the fields from the Request_Content CGI variable.

    'This line decodes the request_content field

    request_content_decoded=fnDecode(doc.request_content(0))

    'This line gets the field you are looking for from the decoded data

    fieldvalue = fnGetRCFieldValue(request_content_decoded,"<fieldname>")

    function fnDecode(inString As String) As String Dim L As String Dim M As String Dim R As String Dim P As Integer P% = Instr(inString,"%") If P%>0 Then L$=Left$(inString,P%-1) M$=Mid$(inString,P%+1,2) R$=Right$(inString,Len(inString)-(P%+2)) fnDecode1 = L$ & Chr(Cint("&h" & M$)) & R$ If Instr(fnDecode1,"%") Then fnDecode1 = fnDecode1(fnDecode1) Else fnDecode1 = inString End If End Function

    Function fnGetRCFieldValue( requestContent$, fieldToGet$ ) As Variant 'Owen Enraght-Moony 28-01-99 'returns: the value of a field in the Request_Content CGI var (case sensitive) Dim search$, retStr$, offset%, ends% search$ = fieldToGet$ & "=" retStr$ = "" offset% = 0 ends% = 0 offset = Instr(requestContent$, search) If (offset <> 0) Then offset = offset + Len(search) ends = Instr(offset, requestContent$, "&") If (ends = 0) Then ends = Len(requestContent$)+1 retStr = Mid(requestContent$, offset, ends-offset) End If fnGetRCFieldValue = Trim$(retStr) End Function

    This method is very handy when you have to run an action from a $$viewTemplate for xx form. You can have as many form tags you like and run different agents for each action button.

    Jake, thanks again for all the great tips. This is my immediate contribution for all the tips I have received from your site.

    1. Re: Another way of passing arguments to an agent

      I have been using a similar technique for a number of years. I have created a lotuscript class to parse the document context and access its fields and just like a notes document e.g. webDoc.GetItemValue("MyFIeld")(0) I then access these fields to create and edit documents with added advantage that Users only have READER access to the database but can submit and edit documents. Although the class does not work with multipart web forms so you cannot upload files. You can also create new forms by just creating web pages and not adding them to the design of the notes database. So no waiting for the Admin department to update the design of the database, just add a couple of new web documents to the database. You can create a whole web site based on just a few forms and views in the design of the database.

      Jake I have already partly modified your forms Validation database to use this method if your interested I can send it to you when i have finished.

      Show the rest of this thread

    2. Re: Another way of passing arguments to an agent

      what are the limitations of the Query string? is it simply a size limitation?

      Show the rest of this thread

    3. RequestContentParser class

      This thread helped me out a LOT today.

      Here's my version of the code for parsing the Request_Content field

      [<br clear="all" /><code>] Public Class RequestContentParser Private psRC As String Private piAmpPos As Integer Sub new(Byval sRequest_Content As String) psRC = sRequest_Content piAmpPos = 0 End Sub Public Function Unescape(Byval s As String) As String Dim iP As Integer Dim sL As String Dim sM As String Dim sR As String iP = Instr(s,"%") If iP <> 0 Then sL = Left$(s,iP-1) sM = Mid$(s,iP+1,2) sR = Mid$(s, iP+3) Unescape = sL & Chr(Cint("&h" & sM)) & Unescape(sR) Else Unescape = s End If End Function Public Function GetNextField(sFieldName As String, sValue As String) As Variant 'boolean, true if successful, false if no more fields Dim iEqPos As Integer Dim iFieldPos As Integer On Error 1 Goto ErrorSub If piAmpPos = -1 Then Error 1 iFieldPos = piAmpPos + 1 iEqPos = Instr(iFieldPos, psRC, "=") If iEqPos = 0 Then Error 1 sFieldName = Mid(psRC, iFieldPos, iEqPos - iFieldPos) piAmpPos = Instr(iEqPos, psRC, "&") If piAmpPos <> 0 Then sValue = Unescape(Mid(psRC, iEqPos + 1, piAmpPos - iEqPos - 1)) Else sValue = Unescape(Mid(psRC, iEqPos + 1)) piAmpPos = -1 'flag that there are no more fields End If GetNextField = True ExitSub: Exit Function ErrorSub: GetNextField = False Resume ExitSub End Function Public Function GetFieldValue(sFieldName As String) As String Dim iAmpPos As Integer Dim iFieldPos As Integer Dim iValPos As Integer Dim sValue As String iFieldPos = Instr("&" + psRC, "&" + sFieldName + "=") If iFieldPos = 0 Then GetFieldValue = "" Else iValPos = Len(sFieldName) + 2 iAmpPos = Instr(iValPos, psRC, "&") If iAmpPos = iValPos Then GetFieldValue = "" Else GetFieldValue = Unescape(Mid(psRC, iValPos, iAmpPos - iValPos)) End If End If End Function End Class [</code>]

      You use it by putting this code in your declarations, and having the line

      From there, you do something like: [<code>] Set Session = New NotesSession Set RCP = New RequestContentParser(Session.DocumentContext.Request_Content(0)) Do while RCP.GetNextDocument(sFieldName, sValue) Print sFieldName + { = "} + sValue + {"<br>} Loop [</code>]

      The GetFirstField method is unnecessary unless you need to start from the begining a second time.

      You can also get a specific field value with GetFieldValue.

      Enjoy, and Thanks!

      Show the rest of this thread

      • avatar
      • Andrea
      • Wed 29 Apr 2009

      Re: Another way of passing arguments to an agent

      Do you know if I can use another char intead "&" in the query string?

      I can't use the "&"...

      Thanks in advance.

      Andrea

  2. How do i get same functionality in a form?

    I want to set the value of one field of a form by passing it a web parameter.

    It is possible to load the parameter from inside the form using this trick ??

    In case it is possible, I'd to know wich event should I code to achieve it.

    Thank you!!

      • avatar
      • ejkr
      • Thu 18 Apr 2002

      Re: How do i get same functionality in a form?

      If your form will have the hidden field called "Query_String" on it and the parameter is on the URL for loading the form, it will work.

      (http://servername/dbname.nsf/formname?openform&Parameter).

      Domino will put the parameters in the hidden field.

    • avatar
    • ejkr
    • Thu 18 Apr 2002

    You are driving me crazy

    Good stuff, but if this is about passing parameters to an agent, why is you sample code full of references to fields on a form (which you do not describe): lines from your sample code below...

    Dim doc As NotesDocument ---This is a document Set doc = s.DocumentContext ---A form open in the browser

    Call ExplodeQueryString (doc.Query_String_Decoded(0) , AgentArgs)

    --Where is the field called "Query_String_Decoded"? --What is the form that holds it? --What are the fields and default value formulas? --If we're using a form, the "Openform" URL can have the parameters --so why use an agent?

    1. You drive me crazy

      Have you *actually* tried to create an agent with this code and then opened it in the browser by typing an "?OpenAgent" URL with some parameters appended to it??

      Until you have don't come here telling me I drive *you* crazy!

      Jake

      Show the rest of this thread

  3. Beware: Query_String_Decoded isn't always there

    We are using "Site Minder" on our Web Mail severs and have found to our dismay, that the Query_String_Decoded variable is blank (Query_String has a value).

    This has caused some of Lotus' code for web mail (R4.6) to fail. The problem has been turned over to the vendor.

    Be sure to check your CGI variables on the production server before using them in your code.

    • avatar
    • Joe
    • Fri 28 Jun 2002

    Maybe I'm missing something?

    Jake,

    I understand the value of pasing arguments to an agent but In this line of code (your example) ../db.nsf/url?OpenAgent&Name=Jake&Age=26&Country=UK

    How are you passing Jake, 26, and UK to the url?

    Are these values hardcoded?

    1. Re: Maybe I'm missing something?

      Does it matter? I don't see your point. How you pass in values is irrelevant...

      Jake -codestore

      Show the rest of this thread

  4. This was a great help. Thanks!

    Jake,

    I know you wrote this a long time ago, but I wanted you to know that it's helped me out tremendously even 3 years later. Thanks for this site.

  5. Agent

    This Code saved my life, Thank you so much!

    1. Re: Agent

      Here is a short java agent that shows how to retrieve the value of Query_String from a Java agent.

      The code retrieves the value of Query_String and then outputs it - does not parse it at all...

      Should be enough code to get someone started in the right direction with Java agent. Derek

      import lotus.domino.*; import java.util.Vector; import java.io.*; public class JavaAgent extends AgentBase {

      public void NotesMain() {

      try { Session session = getSession(); AgentContext agentContext = session.getAgentContext(); Document current_doc = agentContext.getDocumentContext(); // Parse Query String Vector v1 = current_doc.getItemValue("Query_String"); PrintWriter pw = getAgentOutput(); pw.println("Query String: "+v1); } catch(Exception e) { e.printStackTrace(); } } }

    • avatar
    • jFizer
    • Mon 16 Oct 2006

    getArg function.

    String getArg(StringTokenizer vST, String Arg) { while(vST.hasMoreTokens()){ if(vST.nextToken().toLowerCase().equals(Arg)) return vST.nextToken(); } return null; }

  6. Lotus Script Agents

    How to change the status of the documents

    • avatar
    • Harold
    • Wed 18 Mar 2009

    Problems with passing "=" in a parameter?

    Hello,

    when I try to pass the canonical username (CN=Peter Pan...) as an agent parameter, where I have to encode it before (CN%3DPeter+Pan...), then my QUERY_STRING_DECODED only returns "CN" and not the full name. It seems, that I can not pass an encoded "=" as a parameter. Any idea?

    regards, Harold

      • avatar
      • Harold
      • Thu 19 Mar 2009

      Re: Problems with passing

      Solved... I was using a buggy class QSParser from notes.net... never trust someone else code...

    • avatar
    • Andrea
    • Wed 29 Apr 2009

    Help query String

    Do you know if I can use another char intead "&" in the query string?

    I can't use the "&"...

    Thanks in advance.

    Andrea

  7. Thanks a lot for this website!

    Perhaps one hint:

    If the the cgi-variable "Query_String(0)" or "Query_String_Decoded(0)" are empty, create a hidden field with the same name (Query_String or Query_String_Decoded) in your form. This fields automatically get the right value in the web. Then you can use

    doc.Query_String_Decoded(0)

    Greetings,

    David

      • avatar
      • Tib
      • Tue 28 Sep 2010

      I too query_string is empty

      but my web agent is called with url http not by a form

      how do it ? adding &Query_String= in URL does not change...

      Show the rest of this thread

    • avatar
    • MaheswarI.k
    • Thu 1 Jul 2010

    Dear All,

    Thanks for ur posting. Its very useful for me.

    Regards,

    Maheswari.K

    • avatar
    • Duncan Caldwell
    • Thu 21 Oct 2010

    Here is a LS routine I have been using.

    Option Public

    Public nSession As NotesSession

    Public naCurrent As NotesAgent

    Public ndbCurrent As NotesDatabase

    Public ndocCurrent As NotesDocument

    Public ndocUser As NotesDocument

    Public vURLParams List As String

    Sub Initialize

    Set nSession = New NotesSession

    Set naCurrent = nSession.CurrentAgent

    Set ndbCurrent = nSession.CurrentDatabase

    Set ndocCurrent = nSession.DocumentContext

    Call ParseURL

    End Sub

    Sub ParseURL

    On Error Goto CommomErrHandler

    Dim vURL As String

    Dim vPairs As Variant

    Dim vLabel As String

    Dim vData As String

    vURL = ndocCurrent.Query_String(0)

    vPairs = Split(vURL,"&")

    Forall vItem In vPairs

    vDelimiter = Instr(vItem,"=")

    If vDelimiter > 0 Then

    vLabel = Left(vItem,vDelimiter-1)

    vData = Mid(vItem,vDelimiter+1)

    Else

    vLabel = Left(vItem,vDelimiter)

    vData = ""

    End If

    vURLParams(vLabel) = vData

    End Forall

    Exit Sub

    'treats commom errors

    CommomErrHandler:

    'This line displays in browser

    Print "Got error on (" + naCurrent.Name + "-ParseURL) #" + Cstr(Err) + " - " + Error$ + " on line " + Cstr(Erl)

    'This line displays on the Domino server console & logs

    Msgbox "Got error on (" + naCurrent.Name + "-ParseURL) #" + Cstr(Err) + " - " + Error$ + " on line " + Cstr(Erl)

    End Sub

    You can then recall any of the args simply by value = vURLParams("argname")

    e.g. url = htt://server/db.nsf/agent?OpenAgent&city=Boston

    you get the city by city = vURLParams("city")

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:



Navigate other articles in the category "Agents"

« Previous Article Next Article »
Conditional WebQuerySave agents   Creating HTTP Requests using Microsoft's XML Parser

About This Article

Author: Jake Howlett
Category: Agents
Keywords: URL; Arguments; Parse; Query String;

Options

Feedback
Print Friendly

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »