HCL Domino V11 – Directory Synchronzation – Part 4

In this part of the tutorial about Domino V11 Directory Synchronization, we want to take a closer look at the actions that can be performed on DirSync configuration documents.

Enable Configuration

To enable a DirSync configuration, select it in the view and click the Enable button.
You will be presented a dialog box where you can select from 2 options.

Select Run in test mode to simulate the actions that Directory Sync would take but without changing any Domino® data. Make any adjustments needed to the Directory Sync configuration. When you are ready to enable synchronization for real, select Synchronize data.

Next, click OK to close the Activate Directory Sync dialog

DirSync will recognise the new configuration on the next scheduled run.

Disable configuration

To disable a DirSync configuration, select the document in the view and click the Disable button.

Next, click OK to close the Deactivate Directory Sync dialog

A “Disable” request document will be created.

DirSync will disable the configuration on next scheduled run and also delete the request document.

You also have to disable a Directory Sync configuration before changing it. You will get a warning message if you try to edit an enabled Directory Sync configuration.

Resync

You can resync all of the Active Directory data.Resync if you make changes to the Directory Sync Configuration document that affects which data is synced. Resyncing occurs through a Dirsync thread that runs in the background, in parallel with the usual incremental sync.

Next, click OK to close the Resynchronize Selected Directories dialog

A “Resync” request document will be created.

On the server console you will see the following entries when the DirSync task processes the resync request.

[1BE0:0004-1D10] DirSync  Updating SyncAll Request's DirSyncRequestState to 1
[1BE0:0004-1D10] 20.01.2020 06:56:19   DIRSYNC From Active Directory (AD) - Summary (0.001 sec, Start=234776, Adds=0, Modifies=0, Deletes=0, Skips=0, Errors=0, End=234775)
[1BE0:0005-0284] DirSync  Sync all request calling SyncFromLDAPToNAB.
[1BE0:0005-0284] DirSync  resyncall - SyncFromLDAPToNAB completed in: 0.363 seconds
[1BE0:0005-0284] DirSync  Updating SyncAll Request's DirSyncRequestState to 2
[1BE0:0005-0284] 20.01.2020 06:56:26   DIRSYNC Full Resync From Active Directory (AD) - Summary (0.363 sec, Start=0, Adds=3, Modifies=0, Deletes=0, Skips=0, Errors=0, End=234775)
[1BE0:0004-1D10] DirSync  Deleting SyncAll Request
[1BE0:0004-1D10] 20.01.2020 06:57:19   DIRSYNC From Active Directory (AD) - Summary (0.001 sec, Start=234776, Adds=0, Modifies=0, Deletes=0, Skips=0, Errors=0, End=234775)

Resync Issue

There is a small issue with resync when you accidently flag a disabled DirSync configuration for resync.

After you confirm to resynchronize selected Directories, the configuration will be flagged for resync by setting the item DirSyncReset=”1″.

When you now enable the configuration, you would expect a resync of the selected configuration, right?
But that does not happen. The DirSync task starts as soon as it detects the new configuration, but it does neither perform the requested resync nor it resets the DirSyncReset item value.
Even trying to reinitiate the resync fails. You need to remove the DirSyncReset item value by either using an agent or another tool of your choice.

I have created a case with HCL for this (Case# CS0081445)

Issue with Domino Directory file name

If you see the following error message on the server console

[1BE0:0004-1D10] CSyncFromAD::ProcessEntry could not open customer directory -  reason File does not exist

check the Domino Directory file name item value in DirSync configuration. Most likely, the file name is misspelled or the file does not exist on the server. In the BETA version, this resulted in an enabled configuration to be prevented from being disabled. This has been tracked under SPR# MOBNBHUHGD and fixed in Domino V11 GA.


HCL Domino V11 – Directory Synchronzation – Part 3

After you have created a Directory Assistance document in part 2 of this tutorial, that is enabled for Directory Sync, create a Directory Sync Configuration document in the Domino® directory. You use this document to select Directory Sync configuration options and then to enable Directory Sync.

Open your Domino Directory (names.nsf) and navigate to Configuration > Directory > Directory Sync .

Click “Add Directory Sync” to create a new document.

Select a Directory Assistance Domain from the list of configurations in da.nsf.

For an initial sync of all users and/or groups from the selected Active Directory set “Sync all Active Directory users” to Yes.
Select No (default) to sync only Active Directory users who are registered in Domino. If previously set to Yes, any unregistered Active Directory users
synced previously are removed from the Domino directory.
For an Active Directory record to sync with Domino, the Active Directory mail field must match theInternet address field in the Domino directory Person document.

Type in the name of the application that is the target for synchronized users and/or groups into the “Domino Directory file name” field. Typically, this is your primary address book (names.nsf)

As you can see, the “Direction” field is not editable by now. At the moment, only a sync from Active Directory is possible.

One of DirSync’s abilities is to rename synced users in the target Domino directory when the when the users’ common name changes in Active Directory.

If the name of an Active Directory user who is not registered in Domino® changes, the name is automatically updated in the Domino® directory Person document during sync, regardless of this option.
If the user is already registered, a standard administration process Rename Person request is initiated for each name processed.

The Sync frequency settings tells DirSync how frequently the Dirsync task checks for Active Directory changes to synchronize. Default is once a minute.
Resync frequency tells DirSync how often to resync all data from Active Directory, in minutes. Default is 10,000 minutes or approximately once a week. If you don’t want to regularly resync all data, specify 0 ( not recommended).

If you want to synchronize groups, select the types of groups to synchronize. If you don’t want to synchronize groups, do not select either option on the “Synchronization” tab of the DirSync configuration document.

Keep in mind that the groups to be synced must be in the global group scope. If you try to sync local groups, you will receive an error on the Domino server console.

DirSync  DirSync  CSyncFromAD::DoModify - Skipping modification because entry = 'CN=Users,CN=Builtin,DC=ad,DC=fritz,DC=box' is not a valid candidate for a 'group' record.

If you only want to sync a subset of all objects under the configured BaseDN, use an LDAp filter.

After you finished your configuration, save and close the document.

Select the saved configuration in the view, click Enable and select Sychronize Data. Select Run in test mode to simulate the actions that Directory Sync would take but without changing any Domino® data.

If not already done, add the DirSync task to the server’s notes.ini

ServerTasks=Replica,Router,Update,AMgr,Adminp,Sched,CalConn,RnRMgr,Dirsync

and issue the following command on the server console: load DirSync.

DirSync will be started automatically on next server restart.

The Dirsync task begins to run when it detects the configuration document and you should now see an entry similar to this on the server console.

[1BE0:0004-1D10] 19.01.2020 15:34:09   DIRSYNC From Active Directory (AD) - Summary (0.128 sec, Start=210711, Adds=0, Modifies=0, Deletes=0, Skips=0, Errors=0, End=234710)

Look at the Status tab of the Directory Sync Configuration document in the Domino® directory in addition to monitoring the output of Dirsync at the server console and in log.nsf.

Congratulation, you have successfully configured DirSync synchronization.
In the next part we will dig deeper into DirSync features and abilities.


HCL Domino V11 – Directory Synchronzation – Part 2

In part 1 we covered the basic concept of DirSync. In this part, I will explain, how to setup and configure directory assistance.

The first step to configure DirSync is creating a DirSync-enabled directory assistance document in the directory assistance database.

If not already done. To configure directory assistance, you create a directory assistance database from the template DA.NTF, and replicate it to the servers that will use it. A server must have a local replica of a directory assistance database to use directory assistance. Then you add the database file name to the directory assistance database name field in the Domino® Directory Server documents of these servers.

For details about how to setup directory assistance refer to “Directory Assistance” in the HCL Domino Administration Help database.

If you are using an existing directory assistance database, replace its design with the da.ntf template provided with Domino® V11 .

Check the application properties.

Look at the template name in the inherit design from master template section. Hmm, seems to be wrong, isn’t it.

I opened a case with HCL support and got the following reply

I would like to inform you that i have checked the DA.ntf template on Domino Version 9.0.1 & 10.0.1.

On both the version it is showing the same name. I also found an enhancement request to change the DA.ntf template name which has been documented in SPR# CTOE8JRPTC.

So the template name of the DA.nft is not wrong it is as per the design.

Click on “Add Directory Assistance” to create a new document in da.nsf

On the “Basics” tab set select “LDAP” as Domain type and set “Make this domain available to” to “Directory Sync“.
Do not select Notes clients and Internet Authentication/Authorization or LDAP Clients unless you are also using the LDAP directory for these
purposes.

On the LDAP tab enter the hostname of your Active Directory and provide (optional) credentials to connect to that instance.

Click Verify to verify that the user name and password you entered is valid on each host name and to asure that the search base is accessible on each host name using the configured credentials.

Use the Suggest button to look up the host names of LDAP servers listed in your DNS and to search each host name for likely search bases.

Each server process that provides directory services and detects a local directory assistance database configuration loads directory information configured in the directory assistance database into an internal memory table.

During server startup and thereafter at five-minute intervals each server process checks for changes to the directory assistance database configuration and if found, each process reloads its internal memory table to reflect the changes.e the document.

From the server console of the Domino® administration server, run the sh xdir command to confirm that the DirSync configuration in the Directory Assistance document is set up correctly.

You should get a console output similar to this:

You have now completed the first step in configurating DirSync. Part 3 of this tutorial will explain, how to create DirSync Configuration documents.



HCL Domino V11 – Directory Synchronzation – Part 1

When the Domino® server is installed in a Microsoft Windows domain, as an administrator, you typically need to maintain two separate directories for the same set of people and groups.
Maintaining user and group information involves adding entries to both directories, deleting entries, ensuring that passwords are the same when users use Notes® Single Logon, coordinating group membership in both directories, and ensuring that user or group settings, such as email addresses and telephone numbers, are identical.

Prior to HCL Domino® V11 you had to install Domino® Active Directory synchronization as an additional feature. This only worked in a Windows environment. Tools like TDI also work on Linux, but the installation and configuration is not easy and error-prone.

HCL Domino V11 introduces ( and replaces ) a new, integrated task to synchronize users and groups . The task is called Directory Sync or DirSync in short.
DirSync replaces the older Active Directory Synchronization feature, which is now deprecated. The new DirSync feature is a simpler, more effective synchronization tool . In this blog series, I will describe the basic concept and explain, how to setup and configure DirSync.

As an HCL Master, I had the privilege to test DirSync already from the first closed V11 BETA on. The HCL team did a great job answering questions about the feature and also fixing issues as soon as they had been reported in the BETA forum.

A lot of fixes have been included in HCL Domino® V11 GA in 12/2019. There are still a few issues on the list that were not so easy to fix. They will be addressed in HCL Domino® V11.01 and later. If available, I will post case numbers and SPR#.

Also, there are some additional DirSync features in the backlog that will be added in future versions of HCL Domino®.

So, what is DirSync and what can you do with it ?

  • DirSync allows you to sync people and/or group data from an external LDAP directory into the Domino® directory.
  • Currently data from Active Directory can be synced
  • DirSync makes it easy for your HCL Domino® users to address mail to and see details about users in your organization who do not use Notes® such as Microsoft™ Outlook users registered in Active Directory.
  • With this feature, Active Directory users automatically have Person documents in the Domino® directory so that Notes® users can find their addresses and other information.
  • Without Dirsync, Notes® users must know the addresses of the Active Directory users before they can send mail to them, unless Person documents are added for them manually.

DirSync includes the following components:

  • LDAP directory assistance document created in a directory assistance database that is enabled for Directory Sync. A Domino® server uses this document to connect to the Active Directory server for syncing.
  • Directory Sync Configuration document created in the Directory Sync view of the Domino® directory. This document controls which Active Directory fields to sync to Domino® as well as other options.
  • A server task, Dirsync, that runs only on the Domino® administration server, that connects to the Active Directory server regularly to pull person and group changes into the Domino® directory.

What abilities does DirSync provide ?

  • The ability to register Active Directory users in Domino®.
  • The ability for administrators to rename registered Domino® users when their names change in Active Directory. When a user’s common name in Active Directory changes, an administration process request, Rename Common Name is created. Administrators approve the request to initiate a standard administration process rename request.
  • The ability to sync from multiple Active Directory instances into multiple applications that use pubnames.ntf as their template. By today, there are still a couple of issues with this configuration. Hopefully they will be fixed in HCL Domino® V11.0.1. I will come back to that later.

DirSync does not sync the password from an Active Directory into the person document in Domino® directory in HCL Domino® V11. This may or may not change in a future version.

Here is what a DirSync environment could look like

serv01 is the Administration server of the Domino® directory running the DirSync task.
Directory Assistant database (da.nsf) contains configuration documents that describe the configuration for the 2 Active Directory instances to sync users and/or groups from.
Domino® directory database (names.nsf) contains the DirSync configuration documents that are needed for synchronization from the Active Directory instances. (AD)
syncbook.nsf is an additional addressbook. Depending on DirSync configuration in names.nsf, users and/or groups are either synced into the primary Domino® directory names.nsf or the secondary syncbook.nsf.

To access Active Directory and add, delete or modify objects, I use LDAP Admin from http://www.ldapadmin.org and AD Explorer from Microsoft Sysinternals Tools https://docs.microsoft.com/en-us/sysinternals/downloads/adexplorer .

In part 2 of this tutorial I will explain, how to setup and configure the Directory assistant database.


Notes 11 – Splash Screen Redesign

With version 11 of HCL Notes & Domino we also got a new splash screen. To be honest, I think the new screen is butt ugly. The gradient isn’t a proper gradient, and the logos are low quality.

Here is a redesigned splash screen. I have used Krita do create the gradient. In fact there are two gradient on 2 layers. The rest is plain text and some transparent images.

To activate the screen, download the image from here and unzip the archive to a destination of your choice.

Next add the following lines to your client notes.ini file.

HasNotesOverlay=1 
SESPlashPath=<path-to-bmp>

Now restart your client. You should now see the new design.


lnsnmp.exe -Sc fails on Domino V11 GA

I tried to install the SNMP agent on a Domino V11 GA installation on Windows 2016 / 64.

Running lnsnmp.exe -Sc resulted in the following error.

D:\Domino>lnsnmp.exe -Sc
Error opening registry key "Domino"
Error Detail: RegOpenKeyEx error code 2 (The system cannot find the file specified.)
Full key: SOFTWARE\Lotus\Domino\DominoMIB\CurrentVersion
Service deletion failed.

I looked into regedit and found the SOFTWARE/Lotus key to be completely empty.

As a workaround, create the needed keys manually. The keys can be empty.

Now run lnsnmp.exe -Sc again, and the service will be created successfully.

D:\Domino>lnsnmp.exe -Sc
Service creation complete.

DNUG Workshop LotusScript

Am Donnerstag, 21. November 2019 lädt Dich die Fachgruppe Development ab 9 Uhr zu einem besonderen Workshop ein.

Hier erfährst Du alles Wissenswerte zum Einstieg in die Notes-Programmierung.

In den acht Stunden ist zwar keine vollständige Ausbildung möglich, aber eine solide Einführung als Grundlage für eigene Weiterbildung.

Weitere Informationen und Anmeldung unter: https://dnug.de/event/grundausbildung-fuer-neue-notes-entwickler-fuer-azubis-und-quereinsteiger/


NotesUser Activity Class

The NotesUserActivity Class is a customizable LotusScript library that returns database user activity summary information. The usage statistics for the prior day, week, and month since user activity recording began is provided. The number of documents a user or server has read, added, updated or deleted during each session, with the most recent activity first, is returned.

The class returns information that is available from the Notes user interface via the File/Database/Properties menu item, Information tab, Activity section, User Detail button selection. User activity for the specified database must be enabled for this function to work .

The class was created by Alex Elliott of AGECOM (http://www.agecom.com.au). Unfortunately it was only availabe for Windows.

I tried to write a Linux port, but I only had a partial success. The code runs without any issues on Windows.

It also runs fine on a Domino V11 Beta1 server on Linux ( CentOS). But it constantly crashes on Domino 10.0.1 ( with or without FP ) on RHEL.

The crash occurs, when the code tries to get the UserName from the ActivityEntry.

pActivityEntry = puActivity + lEntry * 28
		
CopyMemory dt.Innards(0), pActivityEntry , LEN_DWORD
CopyMemory dt.Innards(1), pActivityEntry + 4 , LEN_DWORD
CopyMemory reads, pActivityEntry + 8 , LEN_WORD
CopyMemory adds, pActivityEntry + 10 , LEN_WORD
CopyMemory updates, pActivityEntry + 12 , LEN_WORD
CopyMemory deletes, pActivityEntry + 14 , LEN_WORD
CopyMemory nonDataReads, pActivityEntry + 16 , LEN_WORD
CopyMemory nonDataAdds, pActivityEntry + 18 , LEN_WORD
CopyMemory nonDataUpdates, pActivityEntry + 20 , LEN_WORD
CopyMemory nonDataDeletes, pActivityEntry + 22 , LEN_WORD
CopyMemory nameOffset, pActivityEntry + 24 , LEN_DWORD		

Dim spUsername As String * MAXUSERNAME
spUsername = Space(MAXUSERNAME)

CopyMemoryString spUsername, puActivity + nameOffset, MAXUSERNAME - 2

Dim sUserName As String
sUserName = Trim(spUsername)

CopyMemory and CopyMemoryString are declared as

Declare Sub TUX_CopyMemory Lib "libc.so.6" Alias "memcpy" _
(hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long)

Declare Sub TUX_CopyMemoryString Lib "libc.so.6" Alias "memcpy" _
(ByVal hpvDest As LMBCS String, ByVal hpvSource As Long, ByVal cbCopy As Long)

I tried using undocumented method “Cmovmem” from libnotes.so but it also crashes on V10 AND V11. I must admit that I do not really know, how to use Cmovmem. I declared it this way:

Declare Sub CopyMemoryString Lib LIB_TUX Alias "Cmovmem"  _
(Byval lpSrc As Long, Byval lpDest As String, Byval lSize As Long)

You can find the code here.

Any help to get it working on V10 for Linux is appreciated.


Be careful when using DAOS and compact -c -ZU

There has been a change in Domino 10.0.1 FP2 how the -ZU switch in the compact task behaves.

SPR# GRHEB8YG4K – Fixed a problem where compact -c -ZU and -ZD failed when attempting to recompress DAOS objects.

-ZU lets you enable LZ1 compression on a database. Prior to the change, you could do a compact -c -ods -upgrade -* -n -v -ZU on all databases and templates on the server.

The -ZU switch did not work on DAOS enabled applications, but those applications were upgraded to the latest ODS using the above command.

As of Domino 10.0.1 FP2, -ZU will pull all attachments of a DAOS enabled application back into the application!

via atnotes.de


LotusScript – Error: Type Mismatch

I ran into an issue with a Variant variable passed from one LotusScript class to another. (error: Type mismatch)

The code reads the first ( and only ) document in a database and gets the values from a multi value item.
The value of this item is stored in a Variant; a getter lets you access the values.


Class ConfigProvider

Public Class ConfigProvider
	
	Private m_settings As Variant
	
	Public Sub New
		Dim session As New NotesSession

		m_settings = _
		FullTrim(session._
		currentDatabase._
		Alldocuments._
		Getfirstdocument()._
		Getitemvalue("settings"))
		
	End Sub

	Public Property Get Settings As Variant
		Settings = m_settings
	End Property
End Class

I access the ConfigProvider from within another class in a different LotusScript library. The code is invoked by an agent


Agent

Option Public
Option Declare
Use "de.eknori.config.provider"
Use "de.eknori.config.consumer"

Sub Initialize
	Dim cc1 As New ConfigConsumer(1)
	Dim cc2 As New ConfigConsumer(2)
	Dim cc3 As New ConfigConsumer(3)
End Sub


Class ConfigConsumer

Public Class ConfigConsumer
	
	Private m_settings As Variant
	
	Public Sub New(flag As integer)
		
		Dim cp As New ConfigProvider
		m_settings = cp.Settings
		
		MsgBox ""
		MsgBox " -------- sample: " + CStr(flag) 
		
		Select Case flag
			Case 1       :  'works
				ForAll t In m_settings
					MsgBox CStr(t)
				End ForAll

			Case 2       : 'works
				Dim i As Integer
				For i = 0 To UBound(cp.Settings)
					MsgBox CStr(cp.Settings(i))
				Next

			Case 3       : 'does not work
				ForAll s In cp.Settings
					MsgBox CStr(s)
				End ForAll
				
			Case Else    : 
				msgbox "Else"
		End Select

	End Sub

End Class

The expected behaviour is that in all cases, the code would print the values from the config document to the console, but …

te amgr run "variant.nsf" 'test'
09/03/2019 07:38:25 AM  AMgr: Start executing agent 'test' in 'variant.nsf'
09/03/2019 07:38:25 AM  Agent Manager: Agent message: 
09/03/2019 07:38:25 AM  Agent Manager: Agent message:  -------- sample: 1
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item1
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item2
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item3
09/03/2019 07:38:25 AM  Agent Manager: Agent message: 
09/03/2019 07:38:25 AM  Agent Manager: Agent message:  -------- sample: 2
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item1
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item2
09/03/2019 07:38:25 AM  Agent Manager: Agent message: item3
09/03/2019 07:38:25 AM  Agent Manager: Agent message: 
09/03/2019 07:38:25 AM  Agent Manager: Agent message:  -------- sample: 3
09/03/2019 07:38:25 AM  Agent Manager: Agent 'test' error: Type mismatch
09/03/2019 07:38:25 AM  AMgr: Agent 'test' in 'variant.nsf' completed execution

This is reproducible on Domino V9.x, V10.x and V11 Beta1

I have attached a small sample database, so you can test in your own environment


ESXI 6.7 update: No space left on device

I have tried to update my VMware ESXi 6.7 host to ESXi-6.7.0-20190802001-standard (Build 14320388) today. On the host’s SSH console, the command to use is:

esxcli software profile update -p ESXi-6.7.0-20190802001-standard -d  https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml 

Unfortunately, this gave me this error:

[InstallationError]
  [Errno 28] No space left on device
        vibs = VMware_locker_tools-light_10.3.10.12406962-14141615 
  Please refer to the log file for more details.

/var/log/esxcli.log only gives that exact message! Still, it should be fairly obvious a problem, there is no disk space left.
Just, there is. The commonly accepted fix for this problem is to enable using your datastore as swap space:

  • Logon to web ui
  • Go to Host, Manage, System
  • Select the Swap entry and change it to be enabled
  • Pick a datastore of your choice, and enable Host cache and Local swap

I wrote about this here https://www.eknori.de/2018-03-18/vmware-esxi-errno-28-no-space-left-on-device-ibmchampion/

Unfortunately, in this situation, host swap already was enabled.

There is though, a workaround. You can use an image that doesn’t have the tools vib included with this command:

esxcli software profile update -p ESXi-6.7.0-20190802001-no-tools -d https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot
 -index.xml

You can then manually install the troublesome vib (if you have a need for tools) with this command:

esxcli software vib install -v https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/esx/vmw/vib20/tools-light/VMware_locker_tools-light_10.3.10.12406962-14141615.vib

Access NotesDatabase Options (extended)

GetOption was introduced to the NotesDatabase class in V6. It allows to determine, if specific options are set or not.

By design, it only accesses $dboptions1 from the database. Other options are stored in $dboptions2 – 4.
Those option bits are not accessible using NotesDatabase.getOption(optionName%).

Here is code to access them.

Public Type DBOPTIONS
options (3) As Long
End Type

Public Const W32_LIB = {nnotes.dll}
Public Const TUX_LIB = {libnotes.so}

Declare Function W32_NSFDbGetOptionsExt Lib W32_LIB Alias {NSFDbGetOptionsExt}_
(ByVal hdb As Long, retDbOptions As DBOPTIONS) As Integer
Declare Function W32_NSFDbOpen Lib W32_LIB Alias {NSFDbOpen}_
(ByVal dbName As String, hDb As Long) As Integer
Declare Function W32_NSFDbClose Lib W32_LIB Alias {NSFDbClose}_
(ByVal hDb As Long) As Integer

Declare Function TUX_NSFDbGetOptionsExt Lib TUX_LIB Alias {NSFDbGetOptionsExt}_
(ByVal hdb As Long, retDbOptions As DBOPTIONS) As Integer
Declare Function TUX_NSFDbOpen Lib TUX_LIB Alias {NSFDbOpen}_
(ByVal dbName As String, hDb As Long) As Integer
Declare Function TUX_NSFDbClose Lib TUX_LIB Alias {NSFDbClose}_
(ByVal hDb As Long) As Integer


Public Function NSFDbGetOptionsExt (hDb As Long, retDbOptions As DBOPTIONS)
	If isDefined("WINDOWS") Then
		NSFDbGetOptionsExt = W32_NSFDbGetOptionsExt(hDb, retDbOptions)
	Else
		NSFDbGetOptionsExt = TUX_NSFDbGetOptionsExt(hDb, retDbOptions)
	End If
End Function

Function NSFDbOpen( db As string, hDB As Long) As Integer
	If isDefined("WINDOWS") Then
		NSFDbOpen = W32_NSFDbOpen(db,hDb)
	Else
		NSFDbOpen = TUX_NSFDbOpen(db,hDb)
	End If
End Function

Function NSFDBClose (hDb As Long)
	If isDefined("WINDOWS") Then
		NSFDbClose = W32_NSFDbClose(hDb)
	Else
		NSFDbClose = TUX_NSFDbClose(hDb)
	End If
End Function

Sample:

Const  DBOPT_IS_IMAP = &amp;h01000000

Sub Initialize
	Dim hDb As Long
	Dim rc As Integer
	Dim sDb As String
	
	Dim retDbOptions As DBOPTIONS
	
	sDb = "serv01/singultus!!mail/buser.nsf"
	
	rc = NSFDbOpen(sDb, hDb)
	
	If rc = 0 Then
		rc =  NSFDbGetOptionsExt (hDb, retDbOptions)
		If retDbOptions.options(1) And DBOPT_IS_IMAP Then
			MsgBox "IMAP enabled"
		Else 
			MsgBox "IMAP not enabled"
		End If
		rc = NSFDbClose(hDb)
	End If
End Sub

I have created an enhancement request for an optional method parameter to access the different optionsStores.
If you think, that this might give you some benefit, pls upvote my idea https://domino.ideas.aha.io/ideas/DDXP-I-508


Get sorted results from DQL queries

NotesDominoQuery by now does not support sorting of the results that come out of a query. John Curtis demoed at DNUG46 in Essen how you can get your results sorted. He showed the code only for a second, so I needed to rewrite it from scratch.

The method that he showed leverages from the new ‘maintainOrder’ property that has been added in V10 to the NotesViewEntryCollection class.

But let us first take a closer look at what is needed to make the code work.

I have a small application where I store code snippets. I can categorize them and also test code locally or against a server.

In my sample, I want to get all documents from that application that have “DEMO” in the subject and output the subject in ascending order.
Next I want to get the documents category in descending order.

Both columns, Subject and Category need to be prepared for sorting. They do not neccessarily have to be sorted initially.

To set the sorting programmatically, I use the ‘Resortview’ method from the NotesView class.
Be aware that the columnName must be the programmatic name of the column.
Here is a sample how to use the ‘ResortView‘ method

Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim vec As NotesViewEntryCollection

Set db = session.currentDataBase
Set view = db.getView("Samples")

' Sort By Subject
Call view.Resortview("Subject", true)
Set vec = view.Allentries

' Sort By Category
Call view.Resortview("category", false)
Set vec = view.Allentries

vec will now contain all view entries sorted ascending by Subject and after the second ResortView it will contail all view entries by Category in descending order.

You can use the following code to print the result to the console

Private Sub printIt(vec As NotesViewEntryCollection, itemName As String)
	Dim ve As NotesViewEntry
	Dim doc As NotesDocument
	Dim item As NotesItem
	Dim s As String
	Set ve = vec.Getfirstentry()
	While (Not ve Is Nothing)
		s = "- no value -"
		Set doc = ve.Document
		Set item = doc.Getfirstitem(itemName)
		If (Not item Is Nothing) Then
			If (item.text <> "") Then
				s = item.text
			End if
		End If
		MsgBox s
		Set ve = vec.Getnextentry(ve)
	Wend
End Sub

Now lets add some code to query for all documents that have “DEMO” in the subject.

By now, DQL does not have the capability to build a query that uses CONTAINS. This will be added in a future version of Notes and Domino.

Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView

Dim vec As NotesViewEntryCollection
Dim ve As NotesViewEntry
Dim col as NotesDocumentCollection
Dim doc As NotesDocument
	
Dim query As String
query = "Subject >= 'DEM' AND  Subject < 'DEN'"
Dim dql As NotesDominoQuery
	
Set db = session.currentDataBase
Set view = db.getView("Samples")

Set dql = db.CreateDominoQuery()
Set col = dql.Execute(query)

Call view.Resortview("Subject", true)
Set vec = view.Allentries
Call vec.Intersect(col, true)
Call printIt(vec, "Subject")

Call view.Resortview("category", false)
Set vec = view.Allentries
Call vec.Intersect(col, true)
Call printIt(vec, "category")

I put the code into an agent and ran that agent from the console. Here is the output.

Happy coding!


Technote: Limitations of NotesHTTPRequest and NotesJSONNavigator with future considerations

If you are already using the NotesHTTPRequest and / or NotesJSONNavigator classes in your code and you are experiencing one of the following issues, here is an important technote for you.

  • SPR# DCONB8VMAV – NotesJSONNavigator is unable to parse JSON content > 64k
  • SPR# ASHEB95LFR – Unable to parse JSON string: Missing a name for object member, offset 1
  • SPR# DCONB8F6JV – bad character conversion happening in NotesHTTPRequest response
  • SPR# ASHEB95LFR – NotesJSONNavigator unable to navigate a string which contains new lines and carriage returns
  • SPR# DCONBB2KNR – NotesJSONNavigator experiencing severe issues when parsing packages with empty string values
  • SPR# JCORBB2KWU – Unable to Post > 64K String in NotesHTTPRequest
  • SPR# DCONBB44T4 – Creating a NotesJSONNavigator from nulled response causes crash

https://www-01.ibm.com/support/docview.wss?uid=ibm10875724


Programmatically Update /Add Database to DQL Design Catalog

For high speed access to internal information about views and view columns, DQL processing uses design data extracted from view notes. Currently this information will be stored in a new database, named GQFdsgn.cat.

It is created using new updall flags. It does not replicate and is solely used as a fast-path tool to access design data at runtime.

Here is some LotusScript code to add / update the design of a named Notes application to the catalog. The NSFDesignHarvest call is currently undocumented. Use it at your own risk.

'DECLARATIONS

Public Const UPDATE_DESIGN_CATALOG = 0
Public Const ADD_TO_DESIGN_CATALOG = 1

Const NNOTES ="nnotes.dll"
Const LIBNOTES ="libnotes.so"

Declare Public Function WIN_NSFDbOpen Lib NNOTES Alias "NSFDbOpen" _
(ByVal dbName As String, hDb As Long) As Integer
Declare Public Function LIN_NSFDbOpen Lib LIBNOTES Alias "NSFDbOpen" _
(ByVal dbName As String, hDb As Long) As Integer
Declare Public Function WIN_NSFDbClose Lib NNOTES Alias "NSFDbClose" _
(ByVal hDb  As Long) As Integer
Declare Public Function LIN_NSFDbClose Lib LIBNOTES Alias "NSFDbClose" _
(ByVal hDb  As Long) As Integer
Declare Public Function WIN_NSFDesignHarvest Lib NNOTES Alias "NSFDesignHarvest" _
(ByVal hDb  As Long, ByVal flag  As Long) As Integer
Declare Public Function LIN_NSFDesignHarvest Lib LIBNOTES Alias "NSFDesignHarvest" _
(ByVal hDb  As Long, ByVal flag  As Long) As Integer

' API FUNCTIONS
Private Function NSFDbOpen( db As String, hDB As Long) As Integer
	If isDefined("WINDOWS") Then
		NSFDbOpen = WIN_NSFDbOpen(db,hDb)
	ElseIf isDefined("LINUX") Then
		NSFDbOpen = LIN_NSFDbOpen(db,hDb)
	End If
End Function

Private Function NSFDbClose (hDb As Long)
	If isDefined("WINDOWS") Then
		NSFDbClose = WIN_NSFDbClose(hDb)
	ElseIf isDefined("LINUX") Then
		NSFDbClose = LIN_NSFDbClose(hDb)
	End If
End Function

Private Function NSFDesignHarvest (hDb As Long, flag As long) As Integer
	If isDefined("WINDOWS") Then
		NSFDesignHarvest = WIN_NSFDesignHarvest(hDb, flag)
	ElseIf isDefined("LINUX") Then
		NSFDesignHarvest = LIN_NSFDesignHarvest(hDb, flag)
	End If
End Function

Public Function catalogDesign(sDb As String, flag As Long) As Integer
	
	Dim hDb As Long
	Dim rc As Integer
	
	If flag > 1 Then flag = 1
	If flag < 0 Then flag = 0
	
	rc = NSFDbOpen(sDb, hDb)
	
	If rc = 0 Then
		rc = NSFDesignHarvest(hDb, flag)
		rc = NSFDbClose(hDb)
	End If
	
	catalogDesign = rc 
	
End Function


Get Linux Version Information

To get some basic information about the installed Linux version you can use uname -a.

This will give you something like

Linux serv03.fritz.box 3.10.0-957.1.3.el7.x86_64 #1 SMP 
Thu Nov 29 14:49:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Well, we get the kernel version and the architecture.

rpm -qia ‘release gives much more information

Name        : nodesource-release
Version     : el7
Release     : 1
Architecture: noarch
Install Date: Thu 29 Nov 2018 09:01:53 AM CET
Group       : System Environment/Base
Size        : 3191
License     : MIT
Signature   : RSA/SHA256, Thu 04 Jan 2018 09:42:19 PM CET, Key ID 5ddbe8d434fa74dd
Source RPM  : nodesource-release-el7-1.src.rpm
Build Date  : Thu 04 Jan 2018 09:40:35 PM CET
Build Host  : luthien
Relocations : (not relocatable)
URL         : http://rpm.nodesource.com/pub_8.x/
Summary     : N|Solid repository configuration
Description :
This package contains the NodeSource NodeJS repository
GPG key as well as configuration for yum.
Name        : redhat-release-server
Version     : 7.4
Release     : 18.el7
Architecture: x86_64
Install Date: Tue 27 Nov 2018 01:50:07 PM CET
Group       : System Environment/Base
Size        : 43146
License     : GPLv2
Signature   : RSA/SHA256, Wed 28 Jun 2017 08:59:19 PM CEST, Key ID 199e2f91fd431d51
Source RPM  : redhat-release-server-7.4-18.el7.src.rpm
Build Date  : Wed 28 Jun 2017 08:36:32 PM CEST
Build Host  : x86-037.build.eng.bos.redhat.com
Relocations : (not relocatable)
Packager    : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
Vendor      : Red Hat, Inc.
Summary     : Red Hat Enterprise Linux Server release file
Description :
Red Hat Enterprise Linux Server release files
Name        : epel-release
Version     : 7
Release     : 11
Architecture: noarch
Install Date: Wed 28 Nov 2018 07:54:48 AM CET
Group       : System Environment/Base
Size        : 24834
License     : GPLv2
Signature   : RSA/SHA256, Mon 02 Oct 2017 07:52:02 PM CEST, Key ID 6a2faea2352c64e5
Source RPM  : epel-release-7-11.src.rpm
Build Date  : Mon 02 Oct 2017 07:45:58 PM CEST
Build Host  : buildvm-ppc64le-05.ppc.fedoraproject.org
Relocations : (not relocatable)
Packager    : Fedora Project
Vendor      : Fedora Project
URL         : http://download.fedoraproject.org/pub/epel
Summary     : Extra Packages for Enterprise Linux repository configuration
Description :
This package contains the Extra Packages for Enterprise Linux (EPEL) repository
GPG key as well as configuration for yum.


Enable/Disable/Sign agents without opening DDE

A couple of days ago, Thomas Adrian posted a new idea on aha.io Allow Enable/Disable/Sign agents from Domino Administrator without opening DDE.

This is a pretty cool idea, I think. Although there already is a great tool available from Ytria ( agentEZ ), handling of agents should be a part of the core features of Notes / Domino.

Notes / Domino contains some of the requested features and for example, you can enable an agent via adminp. You can simply create a new admin request in the admin4.nsf; if you know, which values to set. Unfortunately, this is not documented and you have to do a lot of try and error before the admin request is processed. The advantage of using adminp would be documentation of who did what.
As a downside, you cannot disable an agent; there is no adminp request for that.

Back in 2007, I already demonstrated, how you can add your own adminp requests to the adminp Delete Group Members Using The Administration Process

After reading Thomas’ idea, I decided to spend some hours on building a Domino server addin that would enable / disable or toggle the status of scheduled agents in an application. The application path, agent name and what to do should be passed as parameters to the addin.

Project “AMgr2” was born.

Over the years, I have created my own Notes cAPI CPP framework. This is still work in progress, as I add new methods and properties when I need them.

The framework is a great help when it comes to RAD in Notes / Domino using c/c++. I tried to name methods and properties as close as possible to what we have in LotusScript or Java to make the resulting source code readable and maintainable. Here is an example how I determine if an agent is of type “scheduled” within my framework

bool cNotesAgent::isScheduled() {
		cNotesDocument doc(db_h, agnt_id, OPEN_NOVERIFYDEFAULT);
		cNotesItemText trigger = doc.getItemText("$AssistTrigger");
		if(!trigger.compare("1")) {return TRUE;} else {return FALSE;} 
		}

Most of the magic happens in the framework, so the source code for AMgr2 is pretty short.

// main.h

#ifndef _MAIN_H_
#define _MAIN_H_

#include <string>

#if defined (_MSC_VER) &amp;&amp; !defined(ND64)
#pragma pack(push, 1)
#endif
#include <global.h>
#include <miscerr.h>
#include <addin.h>
#if defined (_MSC_VER) &amp;&amp; !defined (ND64)
#pragma pack(pop)
#endif

#include "cNotesFramework.h"
#include "cNotesAgent.h"
#include "cmdline.h"

#if defined (W64)
#define HANDLE DHANDLE
#undef NOTEHANDLE
#define NOTEHANDLE DHANDLE
#else
#define DHANDLE HANDLE
#undef NOTEHANDLE
#define NOTEHANDLE HANDLE
#endif

#define ADDIN_STATUS_LINE	"AMgr2"
#define APP_NAME	"AMgr2: "
#undef MSG
#define MSG(fmt) APP_NAME fmt
#define ERROR -1
using namespace std;

#endif

// main.cpp

/*
* Amgr2
*
* eknori at eknori dot de  www.eknori.de FEBRUARY 2019
*
* copyright (c) 2019 Ulrich Krause www.eknori.de
*/

#pragma warning(disable:4005) 

#include "main.h"

STATUS LNPUBLIC AddInMain (HMODULE hModule, int argc, char *argv[]) {

	STATUS				error = NOERROR;
	HANDLE				hStatusLine;
	HANDLE				hStatusLineDesc;
	HMODULE				hMod;

	AddInQueryDefaults (&amp;hMod, &amp;hStatusLine);
	AddInDeleteStatusLine (hStatusLine);
	hStatusLineDesc = AddInCreateStatusLine(ADDIN_STATUS_LINE);
	AddInSetDefaults (hMod, hStatusLineDesc);
	AddInSetStatusText("Initialising");

	CmdLine *cmdline = new CmdLine();

	cmdline->addUsage("  amgr2, V1.0.0.0, (c) 2019, Ulrich Krause\n");
	cmdline->addUsage("Usage: lo amgr2 [options] [flags]\n");

	cmdline->addUsage( "Options:\n" );
	cmdline->addUsage( "-d    --db\t\tdatabase path" );
	cmdline->addUsage( "-a    --agent\t\tagent name" );

	cmdline->addUsage( "" );
	cmdline->addUsage( "Flags:\n" );
	cmdline->addUsage( "-h    --help\t\tPrints this help" );
	cmdline->addUsage( "      --enable\tEnable agent" );
	cmdline->addUsage( "      --disable\tDisable agent" );
	cmdline->addUsage( "      --toggle\tToggle agent status" );

	cmdline->setOption( "db", 'd' );
	cmdline->setOption( "agent", 'a' );

	cmdline->setFlag ( "help", 'h' ); 
	cmdline->setFlag ( "enable");
	cmdline->setFlag ( "disable");
	cmdline->setFlag ( "toggle");

	cmdline->processCommandArgs( argc, argv );

	if( ! cmdline->hasOptions()) {
		cmdline->printUsage2();
		delete cmdline;
		return ERROR;
		}

	if( cmdline->getFlag( "help" ) 
		|| cmdline->getFlag( 'h' ) ) {
			cmdline->printUsage2();
			return NOERROR;
		}

	string file_path;
	if( cmdline->getValue( 'd' ) != NULL  
		|| cmdline->getValue( "db" ) != NULL  ){
			file_path = cmdline->getValue( 'd' );
		} 

	string agent_name;
	if( cmdline->getValue( 'a' ) != NULL  
		|| cmdline->getValue( "agent" ) != NULL  ){
			agent_name = cmdline->getValue( 'a' );
		} 

	cNotesDatabase _NotesDatabase;

	try{

		_NotesDatabase.open(
			file_path.c_str());

		cNotesAgent _NotesAgent(
			_NotesDatabase.h, agent_name.c_str());

		if(_NotesAgent.isScheduled()) {

			if( cmdline->getFlag( "enable" )) {
				_NotesAgent.enable();

				AddInLogMessageText(
					MSG("... agent '%s' in database '%s' has been enabled\n"), 
					NOERROR, 
					_NotesAgent.name.c_str(), 
					_NotesDatabase.filePath().c_str());
				}

			if( cmdline->getFlag( "disable" )) {
				_NotesAgent.disable();

				AddInLogMessageText(
					MSG("... agent '%s' in database '%s' has been disabled\n"), 
					NOERROR, 
					_NotesAgent.name.c_str(), 
					_NotesDatabase.filePath().c_str());
				}

			if( cmdline->getFlag( "toggle" )) {
				if(_NotesAgent.isEnabled()) {
					_NotesAgent.disable();

					AddInLogMessageText(
						MSG("... agent '%s' in database '%s' has been disabled\n"), 
						NOERROR, 
						_NotesAgent.name.c_str(), 
						_NotesDatabase.filePath().c_str());
					}
				else {
					_NotesAgent.enable();

					AddInLogMessageText(
						MSG("... agent '%s' in database '%s' has been enabled\n"), 
						NOERROR, 
						_NotesAgent.name.c_str(), 
						_NotesDatabase.filePath().c_str());
					}
				}

			} else { // is_scheduled

				AddInLogMessageText(
					MSG("... agent '%s' in database '%s' is not a scheduled agent\n"), 
					NOERROR, 
					_NotesAgent.name.c_str(), 
					_NotesDatabase.filePath().c_str());

			}

		} catch (cNotesErr&amp; err) {
			delete cmdline;
			_NotesDatabase.close();

			AddInLogMessageText(
				MSG("Notes Error: %s\n"), 
				NOERROR, err.what());
			return ERROR;

		} catch (...) {
			delete cmdline;
			_NotesDatabase.close();

			AddInLogMessageText("Unexpected Error\n", NOERROR);
			return ERROR;
			}

		delete cmdline;
		_NotesDatabase.close();
		return error;
	}

To build the cmdline parser, I use another framework that I wrote a couple of years ago. I used the Boost.Program_options in a couple of other projects before, but it is a lot of overhead for such a small project like AMgr2.
CmdLine is much smaller. Despite of its simplicity, it is reliable and produces nice help screens.

I have not yet published CmdLine on Github. If you are interested in the source code, send me an email and I will send you the sources.

Putting it all together, we get a 64bit binary amgr2.exe Copy it to your Domino program directory and you are ready to go.

Open the Domino server console and type

lo amgr2 -h  and you should get

  amgr2, V1.0.0.0, (c) 2019, Ulrich Krause

  Usage: lo amgr2 [options] [flags]

  Options:

  -d    --db		database path
  -a    --agent		agent name
  
  Flags:

  -h    --help		Prints this help
        --enable	Enable agent
        --disable	Disable agent
        --toggle	Toggle agent status

To enable a scheduled agent in an application type

lo amgr2 -d names.nsf -a test --enable

[219C:0002-1CE8] 17.02.2019 08:39:56   AMgr2: ... agent 'test' in database 'names.nsf' has been enabled 

Use –disable to disable an agent or –toggle to change the status of an agent accordingly.

AMgr2 only works for scheduled agents. If an agent does not match this criteria, you’ll get the following message on the server console

lo amgr2 -d names.nsf -a test2 --toggle

[1F94:0002-15D8] 17.02.2019 08:47:53   AMgr2: ... agent 'test2' in database 'names.nsf' is not a scheduled agent

You also can build a simple Notes application that scans all applications on a server for scheduled agents.
Next you can use NotesSession.SendConsoleCommand to enable / disable / toggle one or more agents.

Here is some sample code

Sub Click(Source As Button)
	Dim session As New NotesSession
	serverName$ = "serv01/singultus"
	consoleCommand$ = Inputbox$("Type command:", _
	"Send console command")
	consoleReturn$ = session.SendConsoleCommand( _
	serverName$, consoleCommand$)
	Messagebox consoleReturn$,, consoleCommand$
End Sub

This might not be what Thomas asked for, but it is a good starting point. There is a lot room for improvements and enhancements. AMgr2 will sign the agent with the server id. This might not always be intended. It is not rocket science to implement code and add a couple of parameters to the cmdline parse to use a different id for signing. It is more work to make sure, this id is stored in a secure place and cnnot be accessed by any unauthorized person.

For now, this is it.

AMgr2 once again proves that you can do everything with Notes / Domino. The creators gave us tools that let us add functionallity that is not in the core code. OK, I admit that c/c++ is not the preferred programming language for most of the Notes / Domino developers.


SyntaxHighlighter Evolved: @Formula Brush

Submitted another plugin to the WordPress plugin directory.

The plugin adds a new brush to the SyntaxHighlighter Evolved plugin to colorize @formula code.

Example:

_exclude:= 
"$FILE":"$Fonts":"Form":"$UpdatedBy":"$Revisions":
"ID":"ModifiedBy":"AddressInvoiceAppartment";
_fld:=@Trim(@ReplaceSubstring(@DocFields; _exclude; @Nothing));
 
"{\"@unid\":\""
+@Text(@DocumentUniqueID)+"\","
+ @Implode ( @Transform (
_fld; "_fn" ; "\"" + _fn + "\":\"" + 
@Text ( @GetField ( _fn) ) + "\"" ) ; "," ) +
"},"