My Entry for Teamstudio’s Spotlight Award

Teamstudio recently had a contest where they wanted you to showcase your applications so that others can see what folks are doing out there and so you could toot your own horn a bit.

My entry was probably a lot less snazzy than the ultimate winners (I haven’t seen them) as I tend to focus on non-public facing utilities and infrastructure improvements in my development work.

But I thought it would be worthwhile posting my entry here (now that they’ve let me know I *didn’t* win… *sniff*) so those of you who know me might get some idea what I spend part of my days doing.

I just call my application the “Admin Agent Repository”. It was originally created to house a single major utility and to serve as a common repository for the myriad agents that are useful for administrators on a day-to-day basis. But I have refined it to allow non-developer administrators access to its functionality.
The most visible application was to buffer us from the rather absolute and immediate nature of Domino’s user termination where the need to reinstate caused a lot of headaches.
A document is created for each terminated employee – this can be created by anybody granted the correct role so security or helpdesk folks can input terms directly – and, on the appointed date the user’s name is submitted to the deny access group.
The app also verifies whether or not the user has a Blackberry device and notifies our Blackberry group to remove their account.

Designed when background agents could not access databases on other servers, the application will then run an agent on the user’s home server and, if necessary, update their database ACL with the name of a person responsible for cleaning up the mail file and send a note, with a link to that responsible individual explaining their responsibilities.
When the purge date arrives (the default is 4 days, 30 if a responsible person is defined,  all controlled via profile), the actual signed adminp request is submitted and the process proceeds as per Domino normal.
Reinstate is often as simple as putting the termination document on hold and removing the user from the deny group. No ACL updates, no repopulating in groups.
The repository is replete with utilities that I have found useful over the years, most are profile driven:

For instance the below profile drives our dynamically created groups. Each morning a subset of our groups are destroyed and recreated based on person document information input by either the users or our identity management system. The groups are used both to control application access based on certain criteria (i.e. all reports to a person can have access to a calendar app used by that team) or for communications (i.e. message to be sent to all folks within a particular state or management structure).

This one inspects all mail files and ensures that they not only have a template, but that it’s one of the standard ones that we mandate:

One ad-hoc utility that is quite popular is one that runs, inspects all of the calendar documents in a mail file and ensures that the $Busyname matches the Owner name from the calendar profile. Very handy for botched renames and transfers of mail files from other domains.
I also have a couple of “Rebuild Busytime” agents for clustered and non-clustered servers that run weekly to keep things there tip-top as well.
These utilities save us literally hours each week, any job that’s wasting my time I invest the effort into automating it and add it to this growing application.

Winmail.dat file issue in Lotus Notes workaround (finally)

Lotus Notes LogoFrom the timestamps I see that this gem has been available since June of 2006 but I certainly had not heard about it.

Microsoft (M$), always there with useful products, also always manages to make things *just* different enough from standard that you can’t really seem to call them on it but they make it impossible to cleanly interface with their products as a competitor.

Case in point is Outlook and Exchange. If you create a message using M$’s email client and send it out the door using their Rich Text Format which seems to be of a proprietary nature, the message that arrives at the other end will be wrapped up in a file called “Winmail.Dat”.

For Lotus Notes this has always been a problem since the Domino server does not have the ability to unravel this proprietary formatting and so the recipient ends up with a useless (winmail.dat )attachment.

I know that there have been some fairly sophisticated attempts at providing solutions but the recipients of these messages are often business users with better things to do than try to master the arcane world of command line utilities with multistep processes.

Until now all we could really tell our users was to contact the sender and have them re-send the message but ensuring that they send with “Plain Text” instead of “RTF”. This is understandably awkward for a business user trying to look professional and it wasn’t doing my ego any wonders either.

The only really practical solution, besides Lotus actually dealing with the issue and including it in their SMTP router is this one presented to me by a co-worker (thanks Anton!). Created by Julian Robichaux (as far as I can tell as his name is all over the database) it is a simple mail-in database that you set up in your Domino environment. Your internal (and external if you wish to help out the rest of the world) Users then forward these nuisance messages to it and it replies back with the “unraveled” files.

So again the link is to Project WinmailExtractor. I had it set up and running in about 15 minutes including inspecting the code for any weirdness.

Marc’s Philosophies – 02

“If you haven’t got the time to do it right,
when will you find the time to do it over?”

This is actually the title of a book that I keep on my desk at work.

The book actually only proved moderately useful in a time management sense (at least for me), but the title is killer. Whenever I get involved in a discussion with someone who wants to do something “quick and dirty and we can circle around and do it properly later” I point to the book and ask the obvious question that is practically bursting from the cover.

I’ve had many arguments around this topic, won most, lost some (when an initiative is being driven by the wrong motivations/people) but this philosophy helps put some perspective on the effort that is about to be expended and helps to guide the thinking and planning process into more strategic pathways.

Cure for Public / Private key mismatch in Lotus Notes

Lotus Notes LogoA fairly common problem in Domino / Lotus Notes is to have a mismatch between the private key in some user’s file and the public key in the Directory (Address Book).

This can come about through a number of ways: restoring a really old copy of a user ID, recreating a user ID without updating the person document are two that spring immediately to mind.

Of course this can be avoided by configuring your servers to enforce key checking on the security tab but that brings with it its own set of access issues for folks from foreign directories.

The problem with public / private key mismatches is that it’s usually not obvious to the end user but it will prevent a bunch of very useful adminp functions from working.

The most obvious symptom for the user, and the main reason the problem normally gets addressed, is when they receive an encrypted message and Lotus Notes reports that “you cannot access portions of this document because it is encrypted and was not intended for you or you do not have the decryption key”.

But from an administration point of view, when this problem is in play, renames do not work, recertifying folks from the directory (as opposed to having them merge a safe ID) will not work and any adminp function that requires a signed request (delegating a mail file if the owner does not have manager access for example) will not work.

The approach I took for this issue was to note that, whenever a user authenticates with a server (which they do when they first try to talk to it with Lotus Notes) a unique message is entered into the log that I can identify with an Event Handler.

Here’s what I did:

– I created a mail-in database (mail-in document in directory, database is located on my administration server, though it really doesn’t matter, I locate most of these kinds of databases on this server. It keeps everything in one place.)

– I created an Event Handler in the events4.nsf database on all my mail servers. It looks for “The public key for” (specify this in the “Events must have this text in the event message” box) with an action to send mail to the address of the above mail-in database.

– In the mail-in database I created two views, one to receive incoming messages from the event handler and one to display the results of the agent that processes them which runs once a day

– I further have 4 forms, one to represent the incoming memos, one for the reports and one each for a public key handler profile (to guide the main agent) and another overall profile – this database was intended to handle more than just the one type of event but so far all I’m dealing with are the public / private key issues.

The database can be downloaded from here. You want to set default access to “No Access” and give yourself manager access.

There are two agents, the minor one just cleans up any reports that are over a month old. Of course you plan for the maintenance cycle up front to keep your databases tidy, right? 🙂 This runs weekly.

The main agent may be of some use all on its own so I include it here. It reviews the items in the “Incoming Memos” view. Probably the only slightly confusing part is that it actually discards the warnings two out of every three days. This is so an affected user doesn’t get bombarded with these messages. The first day the event is triggered, overnight a warning is sent out but the user is going to reauthenticate before they can even see the warning. This would generate another warning even if they take immediate action. The extra day is in there as a grace period. But if the user fails to respond they will receive the warning once every three days until they comply.
You’ll note that the agent below references a script library (included in the above database) that I’ve created and that contains useful functions that I’ve either created or picked up over the years and are common to many of the LotusScript agents that I write. The first thing I ever put into an agent is the error handling since that tends to make troubleshooting a LOT easier.

Option Public
Option Declare
Use “AgentUtils”


Inspect queue of incoming monitor reports and deal with each one as required.

Should be set to run on behalf of “Notes Administrator”


Sub Initialize
Dim sess As New NotesSession
Dim dbCur As NotesDatabase
Dim docProf As NotesDocument
Dim sPrintText As String

Dim viewIncoming As NotesView
Dim docIncoming As Notesdocument
Dim docDel As NotesDocument
Dim docReport As NotesDocument
Dim bNeedReport As Boolean
Dim sRepBody As String

Dim docNotify As NotesDocument
Dim namNotify As NotesName
Dim rtiBody As NotesRichTextItem
Dim itmNotified As Notesitem

On Error Goto ErrorGeneral

Set dbCur = sess.CurrentDatabase

Set docProf = dbCur.GetProfileDocument(“overallProfile”)
If docProf.Notify(0) = “” Then ‘probably not initialized
Print “Overall Profile document not initialized. Agent will not proceed without notifications specified.”
Goto leavesub
End If

sRepBody = “”

‘Walk through all documents in the incoming view
Set docReport = dbCur.CreateDocument
docReport.Form = “Report”
docReport.DateCreated = Now
docReport.Agent =
sRepBody = “Started: ” & Cstr(Now) & Chr$(13) & Chr$(13)

Set viewIncoming = dbCur.GetView(“Incoming”)
If viewIncoming Is Nothing Then
sPrintText = “Problem opening “”Incoming”” view. Terminating agent.”
sRepBody = sRepBody & sPrintText & Chr$(13)
Call ProblemNotify(docProf,sPrintText)
Goto LeaveSubWithReport
End If
Set docIncoming = viewIncoming.GetFirstDocument

While Not docIncoming Is Nothing
‘Identify each type of monitor and direct to appropriate function
If Left$(docIncoming.Subject(0),27) = “WARNING: The public key for” Then
If Not ProcessPublicKeyWarning(docIncoming, sRepBody) Then
‘there was a problem
Goto LeaveSubWithReport
End If
Else ‘If none of the conditions are met, just report on this and throw away
sRepBody = sRepBody & “Unprocessed message from ” & docIncoming.From(0) &_
” with subject “”” & docIncoming.Subject(0) & “””. Message discarded.” & Chr$(13)
End If

Set docDel = docIncoming ‘all messages are deleted by the time the agent has finished.
Set docIncoming = viewIncoming.GetNextDocument(docIncoming)
If Not docDel Is Nothing Then ‘well… delete it
Call docDel.remove(True)
End If

sRepBody = sRepBody & Chr$(13) & “Finished: ” & Cstr(Now)
docReport.Body = sRepBody
Call docReport.Save(True,False)
Exit Sub

sPrintText= “Error: ” + Cstr(Err) + ” defn: ” + Error$ + “. Aborting Agent”
Call ProblemNotify(docProf,sPrintText)
If docReport Is Nothing Then
Resume LeaveSub
Resume LeaveSubWithReport
End If
End Sub

Function ProcessPublicKeyWarning(docIncoming As NotesDocument, sRepBody As String) As Boolean
‘We asssume we only get here if there is a valid subject string in docIncoming
Static sess As Notessession
Static dbCur As NotesDatabase
Static docProf As NotesDocument
Static bSend As Boolean
Static docHoldItem As NotesDocument
Static itmPublicKeyNames As NotesItem
Static itmServerNames As NotesItem
Static itmExceptionNames
Static sExceptionNames() As String
Static itmIgnoreNames
Static sIgnoreNames() As String
Dim docNotify As NotesDocument
Dim sPrintText As String
Dim rtiBody As NotesRichTextItem
Dim sName As String
Dim namSendTo As NotesName
Dim iEndPos As Integer
Dim bExceptionServer As Boolean
Dim namFromServer As NotesName
Dim bExceptionNames As Boolean
Dim iExcpNm As Integer
Dim namExceptionName As NotesName
Dim bIgnoreNames As Boolean
Dim iIgnoreNm As Integer
Dim namIgnoreName As NotesName
Static namExceptionNamesMb As NotesName
Static namExceptionMb As NotesName

Static dbHints As NotesDatabase
Static docHints As NotesDocument

ProcessPublicKeyWarning=False ‘Assume failure
If sess Is Nothing Then
‘for efficiency only want to initialize these variables on the first call.
‘preserve their values across calls
Set sess = New notessession
Set dbCur = sess.currentdatabase
Set docProf = dbCur.GetProfileDocument(“pkProfile”)
If docProf.Notify(0) = “” Then ‘probably not initialized
sPrintText = “Public Key Profile document not initialized. Agent will not proceed without notifications specified.”
sRepBody = sRepBody & sPrintText & Chr$(13)
Call ProblemNotify(docProf,sPrintText)
Goto leaveFunction
End If
Set itmServerNames = docProf.GetFirstItem(“ServerNames”)
Set itmExceptionNames = docProf.GetFirstItem(“ExceptionNames”)
iExcpNm = -1
Forall ExcpNm In itmExceptionNames.values
If Not ExcpNm = “” Then
Set namExceptionName = New NotesName(ExcpNm)
iExcpNm = iExcpNm + 1
Redim Preserve sExceptionNames(iExcpNm)
sExceptionNames(iExcpNm) = Lcase(namExceptionName.Abbreviated)
End If
End Forall

Set itmIgnoreNames = docProf.GetFirstItem(“IgnoreNames”)
iIgnoreNm = -1
Forall IgnoreNm In itmIgnoreNames.values
If Not IgnoreNm = “” Then
Set namIgnoreName = New NotesName(IgnoreNm)
iIgnoreNm = iIgnoreNm + 1
Redim Preserve sIgnoreNames(iIgnoreNm)
sIgnoreNames(iIgnoreNm) = Lcase(namIgnoreName.Abbreviated)
End If
End Forall

If docProf.NextAction(0) = “Send” Then
bSend = True
docProf.NextAction = “Del1”
Elseif docProf.NextAction(0) = “Del1” Then
bSend = False
docProf.NextAction = “Del2”
Elseif docProf.NextAction(0) = “Del2” Then
bSend = False
docProf.NextAction = “Send”
Else ‘ Catch all – just init to send
bSend = False
docProf.NextAction = “Send”
End If
Call docProf.Save(True,False)

If bSend Then ‘ only bother initializing all this if we’re going to use it
‘I send the end user a link to a document explaining how to send me a copy of their public key
Set dbHints = New NotesDatabase(“YourServer”,”common//ourhowto.nsf”) ‘<–CHANGE THIS
Set docHints = dbHints.GetDocumentByUNID(“8037E8A85B57EC8B85256F1E0043B375”) ‘<–CHANGE THIS
If docHints Is Nothing Then ‘couldn’t find the doc
sPrintText = “Can’t find notice in Hints database regarding Mailing Public Keys. Aborting Agent”
sRepBody = sRepBody & sPrintText & Chr$(13)
Call ProblemNotify(docProf,sPrintText)
Goto LeaveFunction
End If
Set docHoldItem = dbCur.CreateDocument
Set itmPublicKeyNames = New NotesItem(docHoldItem,”PublicKeynames”,”Dummyfirstentry”)

Set namExceptionNamesMb = New NotesName(docProf.ExceptionNamesMailbox(0))
Set namExceptionMb = New NotesName(docProf.ExceptionMailbox(0))
End If
End If

iEndPos = Instr (29 ,docIncoming.Subject(0) , “/YOURORG”,5) ‘<–CHANGE THIS – MAKE SURE TO ADD YOUR ORG HERE
If iEndPos = 0 Then ‘Not an YourORG employee, skip
sPrintText = “Can’t find name of YourORG employee in Subject: ” & docIncoming.Subject(0) ‘<–CHANGE THIS
sRepBody = sRepBody & sPrintText & Chr$(13)
Call ProblemNotify(docProf,sPrintText)
‘ “/YourORG” is 8 characters long, the starting point is at 29, so the length will be iEndpos – 21 (29-8) ‘<–CHANGE THIS
sName = Mid$(docIncoming.Subject(0),29,iEndPos -21)
Set namSendTo = New Notesname(sName)

bIgnoreNames = False
bExceptionNames = False
bExceptionServer = False

Forall IgnoreNms In sIgnoreNames
If Lcase(namSendTo.Abbreviated) = IgnoreNms Then
Exit Forall
End If
End Forall

If Not bIgnoreNames Then
Forall ExcpNms In sExceptionNames
If Lcase(namSendTo.Abbreviated) = ExcpNms Then
Exit Forall
End If
End Forall

If Not bExceptionNames Then
Forall srvnm In itmServerNames.Values
If docIncoming.From(0) = srvnm Then
Exit Forall
End If
End Forall
End If
End If

Set namFromServer = New NotesName(docIncoming.from(0))

If bSend And Not bIgnoreNames Then ‘We only want to take action on these every three days. Otherwise we allow the monitor
‘documents to simply be deleted.

If Not itmPublicKeyNames.contains(namSendTo.Abbreviated) Then
Set docNotify = dbCur.CreateDocument
docNotify.Form = “Memo”
docNotify.ReplyTo = “Notes ID”
docNotify.Principal = “YourCompany Notes Monitor” ‘<–CHANGE THIS
docNotify.Subject = “Your Lotus Notes Public Key does not match our copy in the YourORG Directory” ‘<–CHANGE THIS
Set rtiBody = New NotesRichTextItem(docNotify,”Body”)
Call rtiBody.AppendText(“Hi ” & namSendTo.Common & “,”)
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“You are receiving this automated email because our Lotus Notes logs”)
Call rtiBody.AppendText(” show a mismatch between the public key in your Lotus Notes User ID”)
Call rtiBody.AppendText(” file and the corresponding one in our YourORG Directory.”) ‘<–CHANGE THIS
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“This happens most often if you ever had an issue that may have”)
Call rtiBody.AppendText(” required recovery of your Lotus Notes user ID file”)
Call rtiBody.AppendText(” (a damaged or stolen computer is often the cause). “)
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“Please follow this link for directions on how to update your public key “)
Call rtiBody.AppendDocLink(docHints, docHints.subject(0))
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“This should take less than two minutes.”)
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“It will also explain why the mismatched keys are a bad thing that can”)
Call rtiBody.AppendText(” ultimately prevent you from seeing the contents of your incoming mail.”)
Call rtiBody.AddNewline(2)
Call rtiBody.AppendText(“Domino Administrator”)

If bExceptionNames Then
docNotify.Subject = namSendTo.Common & ” – Lotus Notes Public Key does not match our copy in the YourORG Directory” ‘<–CHANGE THIS
Call docNotify.Send(False,docProf.ExceptionNamesMailbox) ‘send to exception Names mailbox if from specified server(s)
‘ Call docNotify.Send(False,”marc Bourassa”)
Elseif bExceptionServer Then
docNotify.Subject = namSendTo.Common & ” – Lotus Notes Public Key does not match our copy in the YourORg Directory” ‘<–CHANGE THIS
Call docNotify.Send(False,docProf.ExceptionMailbox) ‘send to exception mailbox if from specified server(s)
‘ Call docNotify.Send(False,”marc Bourassa”)
docNotify.Subject = “Your Lotus Notes Public Key does not match our copy in the YourORG Directory” ‘<–CHANGE THIS
Call docNotify.Send(False,namSendTo.Canonical)
‘ Call docNotify.Send(False,”marc Bourassa”)
End If
Call itmPublicKeyNames.AppendToTextList(namSendTo.Abbreviated)
If bExceptionNames Then
sRepBody = sRepBody & “[Public Key Mismatch] User: ” & namSendTo.Common &_
” Server: ” & namFromServer.Common &_
” via ” & namExceptionNamesMb.Common & ” [Name Exception]” & Chr$(13)
Elseif bExceptionServer Then
sRepBody = sRepBody & “[Public Key Mismatch] User: ” & namSendTo.Common &_
” Server: ” & namFromServer.Common &_
” via ” & namExceptionMb.Common & ” [Server Exception]” & Chr$(13)
sRepBody = sRepBody & “[Public Key Mismatch] User: ” & namSendTo.Common &_
” Server: ” & namFromServer.Common & Chr$(13)
End If
End If

If bIgnoreNames Then
sRepBody = sRepBody & “[Public Key Mismatch] User: ” & namSendTo.Common &_
” Server: ” & namFromServer.Common &_
” [Ignored]” & Chr$(13)
sPrintText = “[Ignoring Public Key Mismatch] User: ” & namSendTo.Common &_
” Server: ” & namFromServer.Common
sRepBody = sRepBody & sPrintText & Chr$(13)
End If
End If
End If

ProcessPublicKeyWarning=True ‘made it this far, must be OK
Exit Function

End Function

I’ve seen many samples and have taken advantage of a lot of knowledge offered on the web so I thought I could contribute something back. If you do use this code, I’d appreciate it if you referenced this page so that others may find this information if they are looking for solutions.

Autoresponder LotusScript

Below is code to create an automated response whenever someone sends a message to a now obsolete mail file.

It can also be used for a “live” mailbox to indicate something like “We’ve received your message and will respond in 24 hours.”

The only requirements are that the Person document (or mail-in document) must still be present in the directory and a valid name is used in the “Run on Behalf of” field of the agent properties.

Usually this is done for someone who is no longer with the company and so is already in the “Deny Access” groups so using the mailfile owner’s name is often not an option.

It is set up to respond to EVERY message sent to it (unlike the Out of Office Agent) to assure the sender that there message HAS been received.

This particular variation was developed after someone with an autoresponder sent a message to one of our autoresponder  mailboxes and ended up with an endless loop. Messages with identical sender and subject will receive only 1 response per day.

Make sure you customize everything in the agent below that has been bolded.

Agent Information
Name:    Autoresponder – Ensure Unique
Last Modification:    01/03/2008 04:39:40 PM
Comment:    [Not Assigned]
Shared Agent:    Yes
Type:    LotusScript
State:    Disabled
Trigger:    Before New Mail Arrives
Acts On:    Each incoming mail document
LotusScript Code:

Option Public
Option Declare

‘This autoresponder will protect against responses from *other* autoresponders by
‘checking to see if we’ve already received a message from them with the same subject already that day.
‘see the “IsMessageUnique” logic for details
‘Also checks for $AssistMail field which indicates that the message was sent by some
‘automated process. This comes from the case where someone sent a message FROM
‘this inbox TO this inbox and started an endless loop.
‘Note also that there is a name in the “Run on Behalf of” field on the security tab.
‘If this field is populated it *must* be represented in the ACL (At least Reader, probably author is safer) or you
‘will get weird errors when the agent runs.

Sub Initialize
    Dim sess As New NotesSession
    Dim docNotify As NotesDocument
    Dim docCur As NotesDocument
    Dim sPrintText As String
    Dim sMessage As String
    Dim sSendTo As String
    On Error Goto ErrGeneral
    On Error 4294 Goto ErrBadAddress
    Set docCur = sess.DocumentContext
    If Not docCur Is Nothing Then
        If Not Lcase$(docCur.Form(0)) = “nondelivery report” Then  ‘Don’t bother for failed delivery reports
            ‘Only internet messages
        ‘    If docCur.hasitem(“SMTPOriginator”)  Or docCur.hasitem(“MIME_Version”) Or docCur.hasitem(“$MIMETrack”) Then
            If Not docCur.HasItem(“$AssistMail”) Then ‘isn’t sent by another agent
                If IsMessageUnique(docCur) Then
                    Gosub ResponseMessage
                End If
            End If
        ‘    End If
        End If
    End If
    Exit Sub

    Gosub SetupMessage
    Set docNotify = sess.CurrentDatabase.CreateDocument
    docNotify.SaveMessageOnSend = False
    docNotify.Form = “Memo”
    If Not docCur.ReplyTo(0)=”” Then
        sSendTo = docCur.ReplyTo(0)
        sSendTo = docCur.From(0)       
    End If
    docNotify.SendTo = sSendTo
‘Do not need the following fields since this is to be signed by the database owner.
‘if we ever change the signer to “Automail” then these should be set up properly
‘    docNotify.Principal=
‘    docNotify.ReplyTo=
    docNotify.Subject = “re: ” & docCur.subject(0)
    docNotify.Body = sMessage
    Call docNotify.Send(False)
    docCur.EFXResponded= Now
    Call docCur.Save(True,False)

    sMessage= “This is no longer a valid email address for John Doe.  ” &_
    “If you would like you may contact him at, phone – 555-555-5555.“& Chr$(13) & Chr$(13)

    Resume LeaveSub

    sPrintText=    “Error: ” + Cstr(Err) + ” defn: ” + Error$ +  “.  Aborting Agent”
    Call ProblemNotify(sPrintText)   
    Resume LeaveSub
End Sub

Function IsMessageUnique(docCur As NotesDocument) As Boolean
    ‘Check to see if document is the only one with this sender and subject. If so return True
    ‘Otherwise, return false. We expect that multiple messages in a day from the same source with the same subject are probably
    ‘automated responses.
    ‘We only look at the most recent day’s worth of documents, if this doc is for a new day, great,
    ‘or if no match is found for the current day, also great
    Dim sess As New notessession
    Dim viewInbox As NotesView
    Dim docChk  As NotesDocument
    Dim docComp As notesdocument
    Dim bAscending As Boolean
    Dim datRcvd As  Notesdatetime
    Dim datDoc As NotesDateTime
    Dim datComp As NotesDateTime
    Set viewInbox =sess.CurrentDatabase.GetView(“($Inbox)”)
    If viewInbox Is Nothing Then  ‘Returns false
        Exit Function   
    End If
    Set docChk = viewInbox.GetFirstDocument
    Set datDoc = New NotesDateTime(docChk.Created)
    Set docComp= viewInbox.GetLastDocument
    Set datComp = New NotesDateTime(doccomp.Created)
    If datDoc.TimeDifference(datComp) > 0 Then ‘First Document is older than last document, sorted in Descending order
        bAscending = False
        bAscending = True
    End If
    Set datRcvd = New NotesDateTime(docCur.Created)  ‘get created date from newly received document
    Call datRcvd.SetAnyTime
    If bAscending Then
        Set docChk = viewInbox.GetLastDocument
        Set docChk = viewInbox.GetFirstDocument
    End If
    While Not docChk Is Nothing
        Set datDoc = New NotesDateTime(docChk.Created)
        Call datDoc.SetAnyTime
        If Not datDoc.TimeDifference(datRcvd) = 0 Then ‘not sent on same date – either new day or have reached previous day
            Exit Function
        End If
        If docChk.From(0) = docCur.From(0) Then ‘Match, might not be not unique, check subject.
            If docChk.Subject(0) = docCur.Subject(0) Then ‘Match, definitely not unique, end now.
                Exit Function
            End If
        End If
        If viewInbox Is Nothing Then  ‘Returns false
            Exit Function   
        End If
        If bAscending Then
            Set docChk = viewInbox.GetPrevDocument(docChk)
            Set docChk = viewInbox.GetNextDocument(docChk)
        End If
End Function
Sub ProblemNotify(sPrintText As String)
    Dim sess As New NotesSession
    Dim db As NotesDatabase
    Dim docProblem As NotesDocument
    Dim item As NotesItem
    If sess.isonserver Then ‘send an e-mail or print to Log   
        Set db = sess.currentdatabase
        Set docProblem = db.CreateDocument       
        Set Item = docProblem.ReplaceItemValue(“Form”,”Memo”)
        Set Item = docProblem.ReplaceItemValue(“SendTo”,”Your Default Notification Mailbox“)
        Set Item = docProblem.ReplaceItemValue(“Principal”, & ” Agent”)
        Set Item = docProblem.ReplaceItemValue(“Subject”,”Error: ” & db.Title & ” DB – ” & & ” Agent”)       
        Set Item = docProblem.ReplaceItemValue(“Body”,”On ” & db.server & “!!” &db.filepath & Chr$(13) & Chr$(13) & sPrintText)
        Call docProblem.Send(False)
        Print sPrintText
        Messagebox sPrintText,0,”Problem with ” & & ” Agent”
    End If
End Sub

Powered by ScribeFire.

Make the NotesURL property usable

I wanted to be able to get the url for the current document(s) in my mail database so I could paste them in another application and then click on the URLs to access the original messages directly from within that other app as needed.

I cobbled together a little LotusScript agent that grabs the NotesURL from each document and then scrubs out that junk that Lotus includes for no discernible reason.





This script will show the result in a messagebox. I also have it insert the URL into the clipboard for me but I’ve scraped that out so as not to confuse the issue.

It’s not as pretty as I’d like, but this should help others trying to get a useful URL out of Lotus’ terrible implementation.

Dim sess As New NotesSession
Dim doc As NotesDocument
Dim coll As NotesDocumentCollection
Dim sTempURL As String
Dim sURL As String
Dim iPosAT As Integer
Dim iPosSlashUnderscores As Integer
Dim iPosNSF As Integer

Set coll = sess.CurrentDatabase.UnprocessedDocuments
Set doc = coll.GetFirstDocument

sURL = “”
While Not doc Is Nothing
    sTempURL = doc.NotesURL
    iPosSlashUnderscores = Instr(sTempURL,”/__”)
    iPosNSF = Instr(iPosSlashUnderscores+1,sTempURL,”.nsf/”)
    If sess.CurrentDatabase.Server=”” Then
        sTempURL = Left$(sTempURL,8) & “/” & Mid$(sTempURL,iPosSlashUnderscores+3,iPosNSF-iPosSlashUnderscores-3) & Mid$(sTempURL,iPosNSF+4)
        sTempURL = Left$(sTempURL,iPosAT-1) & “/” &    Mid$(sTempURL,iPosSlashUnderscores+3,iPosNSF-iPosSlashUnderscores-3) & Mid$(sTempURL,iPosNSF+4)
    End If

    sURL = sURL & sTempURL
    Set doc = coll.GetNextDocument(doc)
    If Not doc Is Nothing Then
        sURL = sURL & Chr$(13)
    End If
If sURL = “” Then
    Messagebox “No Documents Selected”,0,”Nothing to do”
    Messagebox sURL,0,”URL(s) for selected docs”
End If

(also posted in