Expand group names

Ofte har man brug for at konvertere et gruppenavn til en liste med personnavne. Dette kan nemt gøres med @ExpandNameList funktionen – men den virker kun på Mail grupper og personer der bruger Notes mail.Så her en lidt tungere variant der virker på alle gruppe og person typer:
Use "cls.system"
%REM
	Resolves a mixed list of groups and usernames - Explodes the groups and returns a list with all usernames
%END REM
Function resolveMembers( GroupOrNameList As Variant ) As Variant
	On Error GoTo eh
	Dim members As Variant
	Dim group As NotesDocument
	Dim person As NotesDocument
	Dim v As Variant

	'find a server (use the homeserver if script is running on a local database)
	Dim server As Variant
	server = Evaluate(|@if( @subset( @dbname;1 ) = ""; @LocationGetInfo([HomeServer]); @subset( @dbname;1 ))|)

	dim namelist as variant
	namelist = cList( GroupOrNameList ) 'convert to array

	ForAll member In namelist
		'find the group in names.nsf
		Set group = CacheManager.getDocument( server( 0 ) & "!!names.nsf", "($VIMGroups)", CStr( member ))
		If Not group Is Nothing Then
			v = resolveMembers( group.members )
		Else
			Set person = CacheManager.getDocument( server( 0 ) & "!!names.nsf", "($Users)", CStr( member ))
			If person Is Nothing then
				v = cList( member ) 'if not found - then just add
			Else
				v = cList( person.fullname( 0 ))
			End if
		End If

		If IsEmpty( members ) Then
			members = v
		Else
			members = ArrayAppend( members, v)
		End If
	End ForAll

	'return
	resolveMembers = ArrayUnique( members )

done:
	Exit Function
eh:
	Error Err, getErrorInfo( Me )
End Function

Bemærk: Ovenstående benytter script biblioteket cls.system som du kan finde i Developer Toolbox

Problem med db.GetProfileDocument

Nedenstående kodestump får fat i et profile dokument i basen – men hvis profil dokumentet ikke findes – så bliver det oprettet.

set profile = db.getProfileDocument( "ProfileName" )

Dette kan give problemer hvis en bruger benytter en lokal replika der ikke er replikeret færdigt. Her vil han få oprettet et nyt profile dokument – som overskriver (sletter) det oprindelige profil dokument næste gang der replikeres. Har selv stødt på dette problem et par gange.

Dermed: Inden du læser fra et profil dokumentet via Lotus Script, så er det god skik at checke om det findes. Dette kan gøres på 2 måder:

v = evaluate( |@GetProfileField( "ProfileName"; "FieldName" )| )

eller

Set coll = db.GetProfileDocCollection("ProfileName")
If coll.Count > 0 Then
   Set profile = db.GetProfileDocument("ProfileName")
End If

I script bibliotektet cls.system (som bl.a. findes i Developer Toolbox) kan du finde funktionen hasProfile( db, profilename ) – denne checker om et givent profil dokument findes i basen.

Problemer med doc.send() fra Notes klienten

Jeg bruger ofte doc.send() til at sende en mail fra Lotus Script. Hvis dette gøres fra klienten og brugeren benytter “Recent Contacts” og “Exhaustively check all address books” så kan der opstå Ambigious names (dupletter med forskellige email adresse).

Hvis der sendes til én modtager og navnet er ambigious – så kommer der en fejl, der kan fanges med ‘On error 4295 goto…’ Hvis der derimod sendes til flere modtagere og blot en af adressene virker – så bliver alle ambigious names ignoreret! Dvs. modtagerne får ingen mail – og afsenderen får ingen fejl.

Dette kan dog løses ved at appende et @domain navn til alle email adresser. Dermed bliver navnet ikke resolvet på klienten, men først på serveren hvor problemet ikke findes.

I stedet for doc.send false så kan vi bruge doc.send false, fixRecipients( doc.sendto )

%REM
                 Due to a bug in Notes, Technote 1153854 and the SPR# EMMS2YMU3J:
                 - https://www-304.ibm.com/support/docview.wss?uid=swg21316108
%END REM
Function fixRecipients( source As Variant ) As Variant
                 Dim session As New NotesSession
                 If session.Isonserver Then GoTo done 'not nessesary on the server (client fix only)
                 Dim i As Integer
                 If Not IsArray( source ) Then source = Split( source, "!#¤%&" )
                 
                 Dim s As String
                 
                 For i = 0 To UBound( source )
                                   s = source( i )
                                   s = session.Createname(s).Abbreviated
                                   If InStr( 1, s, "/DomainName", 5 ) > 0 And InStr( s, "@" ) = 0 Then
                                                    s = s & "@DomainName"
                                                    source( i ) = s
                                   End If
                 Next
                 
done:
                 fixRecipients = source
End Function

Links

Lotus Script observationer

Vær opmærksom på at retur værdier fra funktionskald kan blive recyklet. I nedenstående eksempel returnerer funktionen GetArray et array:

Forall entry in GetArray()
   print entry
End Forall

Men koden virker ikke altid idet retur værdien fra getArray bliver recyklet (og ‘print entry’ vil give en Type Mismatch fejl). Gem i stedet returværdien i en lokal variable:

v = GetArray()
Forall entry in v
    print entry
End Forall

Ligeledes bør funktions parameter altid være variable. F.eks. vil nedenstående eksempel fejle i linirn ‘Print db.title’ med en ‘Object Variable not set’:

Call foo( nothing )
Function foo( db as notesDatabase )
    Set db = Session.currentDatabase
    Print db.title
End Function

Brug i stedet en lokal variable:

Set v = nothing
Call foo( v )

 

 

 

 

@ExpandNameList

Nice (but undocumented) function to expand a group:

@ExpandNameList( server:file; groupname )

Has been there since release 5, but it still works.

Updated 09.11.2011

Notice: @ExpandNameList will only work on Mail groups – ‘Access Control List only’ groups are not included (will return an empty array).

Sample script to resolve a list with mixed groups and functions:

%REM
Find all members in a group or list of groups and persons
Will also work when running on a local replica (but requires server access)
%ENDREM
Function getMembers( GroupOrNameList As Variant ) As Variant 

        Dim members As Variant 

        'find a server (use the homeserver if script is running on a local database)
        Dim server As Variant
        server = Evaluate(|@if( @subset( @dbname;1 ) = ""; @LocationGetInfo([HomeServer]); @subset( @dbname;1 ))|) 

        If Isarray( GroupOrNameList ) Then
                Forall member In GroupOrNameList
                        If Isempty( members ) Then
                                members = getMembers( member )
                        Else
                                members = Arrayappend( members, getMembers( member ))
                        End If
                End Forall
        Else
                members = Evaluate(|@ExpandNameList( "| & server( 0 ) & |":"names.nsf"; "| & GroupOrNameList & |" )|)
        End If 

                'fix problem with persons with an forward address on the person document
        Dim i As Integer
        Dim v As Variant
        For i=0 To Ubound(members)
                If lcase( Left(members(i), 3))<>"cn=" Then
                        v = Evaluate(|@NameLookup( [NoUpdate] ; "|+members(i)+|"; "fullname")|) 

                        if v( 0 ) = "" then
                                v = Evaluate(|@NameLookup( [NoUpdate] ; "|+strleftback( members(i), "@" )+|"; "fullname")|)
                        end if 

                        If Not Isempty(v) Then
                                members(i)=v(0)
                        End If
                End If
        Next 

                'remove duplets
        members = Arrayunique( members,5 ) 

                'return
        getMembers = members
End Function

Links