LS/API ClipBoard Code for 32/64Bit

When HCL introduced the 64 Bit Notes Client, the code to set and get data from the clipboard stopped working.

Here is some updated code. It works on HCL Notes 14 64 Bit. I have not tested on V12 64 bit, but it should work on this version too.

%REM
	Library lib_clipboard32-64
	Created Mar 4, 2024 by francesco@marzolo.com
	Modified Mar 5, 2024 by Ulrich Krause
	Description: Allows 64-32 bitness clipboard managing
%END REM
Option Public
Option Declare

Const CF_UNICODETEXT = 13
Const CF_TEXT = 1
Const OS_TRANSLATE_UNICODE_TO_LMBCS = 23

Const LSI_THREAD_PROC=1
Const LSI_THREAD_CALLPROC=10

Public Const GHND = &H42

'** 32-bit API calls
Declare Function OpenClipboard Lib "user32.dll" (ByVal hwnd As Long) As Long
Declare Function CloseClipboard Lib "user32.dll" () As Long
Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long

Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long 
Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long

Declare Function OSTranslateFromPtr Lib "nnotes.dll" Alias "OSTranslate" ( _
	ByVal mode As Integer, _
	ByVal strIn As Long, _
	ByVal lenIn As Integer, _
	ByVal strOut As LMBCS String, _
	ByVal lenOut As Integer ) As Integer

'** 64-bit API calls
Declare Function OpenClipboard_64 Lib "user32.dll" Alias "OpenClipboard" (ByVal hwnd As double) As Long	'** hwnd is a window handle 
Declare Function GetClipboardData_64 Lib "user32.dll" Alias "GetClipboardData" (ByVal wFormat As Long) As Double	'** returns a memory handle
Declare Function CloseClipboard_64 Lib "user32.dll" Alias "CloseClipboard" () As Long

Declare Function GlobalLock_64 Lib "kernel32.dll" Alias "GlobalLock" (ByVal hMem As Double) As Double	'** hMem is a memory handle, returns a pointer
Declare Function GlobalUnlock_64 Lib "kernel32.dll" Alias "GlobalUnlock" (ByVal hMem As Double) As Long	'** hMem is a memory handle, returns a BOOL 
Declare Function GlobalSize_64 Lib "kernel32.dll" Alias "GlobalSize" (ByVal hMem As Double) As Long	'** hMem is a memory handle, returns a size

Declare Function OSTranslateFromPtr_64 Lib "nnotes.dll" Alias "OSTranslate" ( _
	ByVal mode As Integer, _
	ByVal strIn As Double,	_ '** strIn is a string pointer
	ByVal lenIn As Integer, _
	ByVal strOut As LMBCS String, _
	ByVal lenOut As Integer ) As Integer
	
	
'to set clipboard
Private Const GMEM_MOVEABLE = &H40
Private Const GMEM_ZEROINIT = &H2
Declare Function EmptyClipboard Lib "user32" () As Long
Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Declare Function IsClipboardFormatAvailable Lib "user32"  (ByVal wFormat As Long) As Long
Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long	'** returns a memory handle
Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As Long, ByVal lpString2 As String) As Long
Declare Function GlobalAlloc_64 Lib "kernel32" Alias "GlobalAlloc" (ByVal wFlags As Long, ByVal dwBytes As Long) As Double	'** returns a memory handle

Declare Function NEMGetCurrentSubprogramWindow Lib "nnotesws.dll" () As Long

Declare Function SetClipboardData_64 Lib "user32" Alias "SetClipboardData" (ByVal wFormat As Long, ByVal hMem As Double) As Long




Sub Initialize
	
End Sub
Sub Terminate
	
End Sub




Public Function GetClipboard() As String
	Dim session As New NotesSession
	If (session.Platform = "Windows/64") Then
		GetClipboard = GetClipboard64()
		Exit Function
	End If
	

	Dim glbHandle As Long 
	Dim cbPointer As Long
	Dim cbPointerLen As Long 
	Dim cbString As String

	If OpenClipboard(0) Then
		glbHandle = GetClipboardData(CF_UNICODETEXT) 
		cbPointer = GlobalLock(glbHandle) 
		cbPointerLen = GlobalSize(glbHandle)

		cbString = Space(cbPointerLen)
		Call OSTranslateFromPtr( OS_TRANSLATE_UNICODE_TO_LMBCS, _
		cbPointer, cbPointerLen, cbString, cbPointerLen ) 
		cbString = StrLeft(cbString, Chr(0))

		Call GlobalUnlock(glbHandle) 
		Call CloseClipboard()
	End If

	GetClipboard = cbString
End Function
Public Sub SetClipboard(txt As String)
	Dim session As New NotesSession
	If (session.Platform = "Windows/64") Then
		SetClipboard64(txt)
		Exit Sub
	End If
	
	Dim hwnd As Long
	Dim hGlobalMemory As Long
	Dim lpGlobalMemory As Long
	Dim ret As Long
	
	On Error GoTo error_handler
	
' Get a handle to current window
	hwnd = NEMGetCurrentSubProgramWindow()
	If hwnd Then
' Allocate memory
		hGlobalMemory = GlobalAlloc(CLng(GMEM_MOVEABLE Or GMEM_ZEROINIT),CLng(Len(txt)+1))
		If hGlobalMemory Then
			lpGlobalMemory = GlobalLock(hGlobalMemory)
			If lpGlobalMemory Then
				ret = lstrcpy(lpGlobalMemory, txt)
				Call GlobalUnlock(hGlobalMemory)
				If OpenClipboard(hwnd) Then
					ret = EmptyClipboard()
					ret = SetClipboardData(CF_TEXT, hGlobalMemory)
					ret = CloseClipboard()
				End If
			Else
				MsgBox "Can't allocated global memory pointer.", 32, "Error"
			End If
		Else
			MsgBox "Can't allocated global memory handle.", 32, "Error"
		End If
	Else
		MsgBox "Can't get window handle.", 32, "Error"
	End If
	Exit Sub
error_handler:
	Print "Error: " + Error$(Err)
	Resume Next
End Sub

Function describeError() As String
	describeError=Error & " (at row " & Erl & " of " & GetThreadInfo(LSI_THREAD_CALLPROC) & ")"
End Function


Function GetClipboard64() As String
	On Error GoTo sbreng
	Dim session As New NotesSession
	session.UseDoubleAsPointer = True
	Dim glbHandle_64 As Double
	Dim cbPointer_64 As Double
	Dim cbPointerLen As Long
	Dim cbString As String

	If OpenClipboard_64(0) Then
		glbHandle_64 = GetClipboardData_64(CF_UNICODETEXT) 
		cbPointer_64 = GlobalLock_64(glbHandle_64) 
		cbPointerLen = GlobalSize_64(glbHandle_64)

		cbString = Space(cbPointerLen)
		Call OSTranslateFromPtr_64( OS_TRANSLATE_UNICODE_TO_LMBCS, cbPointer_64, cbPointerLen, cbString, cbPointerLen ) 
		cbString = StrLeft(cbString, Chr(0))

		Call GlobalUnlock_64(glbHandle_64)
		Call CloseClipboard_64()
	End If
	GetClipboard64=cbString
	
endop:
	session.UseDoubleAsPointer = False
	Exit Function
sbreng:
	Dim errmsg$
	errmsg$="Error: " & Err & ", call stack: " &  describeerror()
	Print errmsg
	'ensure you execute anyway useDoubleAsPointer=False
	Resume endop
End Function
Function SetClipboard64(txt As String)

	Dim session As New NotesSession
	session.UseDoubleAsPointer = True
	
	Dim hGlobalMemory As Long
	Dim lpGlobalMemory As Long
	Dim hClipMemory As Long
	Dim X As Long
	
	hGlobalMemory = GlobalAlloc(GHND, Len(txt) + 1)
	lpGlobalMemory = GlobalLock(hGlobalMemory)
	lpGlobalMemory = lstrcpy(lpGlobalMemory, txt)
	
	If GlobalUnlock(hGlobalMemory) <> 0 Then
		MsgBox "Could not unlock memory location. Copy aborted."
		GoTo OutOfHere2
	End If
	
	If OpenClipboard(0&) = 0 Then
		MsgBox "Could not open the Clipboard. Copy aborted."
		Exit Function
	End If
	
	X = EmptyClipboard()
	hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory)
	
OutOfHere2:
	If CloseClipboard() = 0 Then
		MsgBox "Could not close Clipboard."
	End If
	session.UseDoubleAsPointer = False
End Function

HCL Notes Client – “Invalid RTF Data On The Clipboard”

The issue applies to HCL Notes 12.0.1 standard and basic as well as HCL Notes 12.0.2 32/64Bit standard and basic.

When you try to change your signature in the Calendar Profile, you get the error message

Theo Heselmans initially reported this issue last week. HCL provided 1202SHF12_W32 yesterday. I have asked for a 64 bit version but have not yet receiced an answer.

The 32 bit version fixes the issue for the 32 bit client.


Issue with NotesUIWorkspace.Prompt on 12.0.2 64/32Bit

Daniele Grillo (grydan.it) has brought to my attention a bug related to HCL Domino Designer 12.0.2 64Bit.
If the NotesUIWorkspace.Prompt method is used in LotusScript with certain types, and the script is created in Domino Designer 12.0.2 64Bit, the function calls do not work in HCL Notes 12.0.2 32bit.
In detail these are the types

  • PROMPT_OKCANCELLIST
  • PROMPT_OKCANCELCOMBO
  • PROMPT_OKCANCELEDITCOMBO
  • PROMPT_OKCANCELLISTMULTI


The issue has been confirmed by HCL Support and is tracked under SPR# PSHECLNFST.

I have created a small database that you can use to test the behavior yourself.


Domino Designer 12.0.2 – Object and Agent list is empty

The issue applies to the 32 and 64 bit of the Domino Designer 12.0.2. It occurs in Forms, Views and Folders.

Also, the issue only occurs when you open an application in Designer from the Notes workspace.

When you open an application in Domino Designer and edit i. e. a view, you expect a list of (default) agents and also a list of available objects as shown in the following image.

When you open the application in Domino Designer from the Notes Workspace, you will see this

UPDATE:

I have found the trigger. It is related to the width of the tab navigation. I have a Marvel client configuration for it, which sets the value of the Workspace_Navigator_Width variable to 55. With this, only the colored squares are visible.

If one now opens an application in the designer via the right mouse button, the objects and agents are only visible as symbols. If you change the width (at runtime), the objects and agents become visible again.

Here is a short video demoing the issue.

HCL support was able to reproduce. the issue is being tracked under SPR# ASHECLEFDF


Upgrade VMWare ESXi 7.0.x to 8.0.0

If you are running VMWare 7.0.3 and intend to upgrade to the new major release 8.0.0, I recommend to wait for a few days. 8.0.0 needs a new license, but the registration process is broken by now.

If you upgrade now, ESXi will run in evaluation mode only for the next 60 days.


DOTS – “An error occurred while processing the command”

If you are using DOTS in Domino 12.x, you might have seen some NullPointer Exceptions after you have updated a DOTS plugin. Recommendation was to delete the complete workspace-dots folder prior to starting DOTS after the upgrade.

This issue has been addressed in SPR# SJAAC3BNWV: DOTS – Workspace need to be deleted on every change and add of new plugin.

With this fix it is no longer necessary to delete the workspace-dots folder. Not sure, when the fix was provided. There is no information about it in the fix list database.

But this is only true for Domino on WINDOWS. If you are using DOTS with Domino on LINUX, you will see an error on the Domino server console ( “An error occurred while processing the command”) or even worse, the NullPointer Exceptions.

The problem is that the underlying API in Domino does not delete files starting with a dot. (hidden files on UNIX systems).

There is a HF67 available for Domino 12.0.1 FP1 that fixes this issue. SPR# DNADCHM8VJ: Deleting directory fails on Linux/UNIX when directory contains files starting with dot (UNIX hidden file).

The fix has already found it’s way into Domino 12.0.2 (Danube).

If you need the fix, open a case with HCL support.


NotesException: Object has been removed or recycled

A few days ago, a customer reported that one of our applications was not working properly and sent the associated logs.

It was very quickly clear under what conditions the error occurred. So it was reproducible, which is the first important step to troubleshooting.

Nevertheless, it took some time to locate the cause. Finally, I was able to find the “error”. To send it ahead. The “error” is not limited to a specific Domino version. The problem also occurs under Domino 9.0.1 FP10.

To illustrate the problem I wrote a small Java agent.
When we work with Java in the Domino environment, one of the best practices is to recycle Domino objects. We do this in countless places in our applications, and it hasn’t really caused a problem yet.

Not so in this particular case. Let’s take a look at the code of the agent.

import lotus.domino.*;

public class JavaAgent extends AgentBase {

	Database db = null;

	public void NotesMain() {

		DocumentCollection col = null;
		Document doc = null;

		try {
			Session session = getSession();
			db = session.getCurrentDatabase();
			col = db.getAllDocuments();
			
			doc = db.getDocumentByUNID(col.getFirstDocument().getUniversalID());
			
			if (null != doc) {
				System.out.println("MAIN: " + doc.getItemValueString("Subject"));
				foo(doc);
				System.out.println("MAIN_2: " + doc.getItemValueString("Subject"));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void foo(Document doc) {
		try {

			System.out.println("FOO: " + doc.getItemValueString("Subject"));
			bar(doc.getUniversalID());

		} catch (NotesException e) {
			e.printStackTrace();
		}
	}

	public void bar(String unid) {
		Document doc2 = null;

		try {
			doc2 = db.getDocumentByUNID(unid);
			System.out.println("BAR: " + doc2.getItemValueString("Subject"));

		} catch (Exception e) {
			e.printStackTrace();
		} finally {

			try {
				doc2.recycle();
			} catch (NotesException e) {
				// fail silent
			}
		}
	}
}

My test database contains a single document. The document has an item “Subject”.
In the MAIN method of the agent we fetch the document and get the UNID.
Now we get the document via this UNID and assign it to the LOCAL variable doc.

On the Domino console we display the content of the item Subject.
Then we branch to the method FOO, and pass the object doc as parameter.
Here, too, we display the contents of Subject.

Now we branch to another method BAR. Since the method is called from many places in the real application, and the document is not available everywhere, we pass the UNID and assign the document found via db.getDocumentByUNID to the LOCAL variable doc2.

Again, we display the contents of Subject. So far everything is OK. When leaving BAR, the LOCAL variable doc2 is recycled and we return to MAIN, where we again display the contents of the item Subject.

And exactly at this point we get an error message. (line 22)

AMgr: Start executing agent 'test' in 'java.nsf' 
Agent Manager: Agent printing: MAIN: I am a sampe document 
Agent Manager: Agent printing: FOO: I am a sampe document 
Agent Manager: Agent printing: BAR: I am a sampe document 
Agent Manager: Agent  error: NotesException: Object has been removed or recycled 
Agent Manager: Agent  error:   at lotus.domino.local.NotesBase.CheckObject(Unknown Source) 
Agent Manager: Agent  error:   at lotus.domino.local.Document.getItemValueString(Unknown Source) 
Agent Manager: Agent  error:   at JavaAgent.NotesMain(JavaAgent.java:22) 
Agent Manager: Agent  error:   at lotus.domino.AgentBase.runNotes(Unknown Source) 
Agent Manager: Agent  error:   at lotus.domino.NotesThread.run(Unknown Source) 
AMgr: Agent 'test' in 'java.nsf' completed execution

If we remove the doc2.recycle() in the finally block of the BAR method, then the agent works as expected.

Looks like a db.getDocumentByUNID() references to the same cAPI backend Object and the object is discarded when it is recycled anywhere in the code flow, regardless if it is assigned to different LOCAL variables.

Not sure, if this is a BUG in Domino, or if it is considered as work as designed. Will open a case with HCL support.

I am totally baffled that no one has encountered this problem yet.
I have also always been under the (obviously) mistaken assumption that LOCAL variables are treated as such.


ESXi 7.x and beyond , SD cards & system storage layout

I am using VMWare ESXi since version 4 was shipped in 2009 in both, home lab and enterprise scale installations. The product evolved over the years, and it worked mostly reliable; except a couple of minor glitches in the matrix. Best of all. It is FREE.

If you are running a home lab, resources are limited. there is a 50% chance that you are running the ESXi from a USB flash drive or SD card.

Although it is and was never recommended by VMWare it works. I saw a few USB sticks dying over the years. When that happened for the very first time, I panicked. Today, I know better.

Simply reinstall ESXi on a new device, boot the server, apply your license and register your VMs. Takes 5 minutes, and you are back on track.

ESXi 7.x is the current release, and VSphere.next ( version 8 ) will come out soon. There are already a lot of articles around where VMware announced not to support USB / SD devices as a boot device. But they revised guidance in VMWare KB 85685

VMware will continue supporting USB/SD card as a boot device through the 8.0 product release, including the update releases. Both installs and upgrades will be supported on USB/SD cards.

I encourage you to read VMware KB 85685 in its entirety. The information is critical to ANY virtualization home lab enthusiast, and/or any VMware administrator who is planning out how and where they’ll be installing or upgrading to VMware ESXi 8.0 hypervisor.

Here is an image that shows the changes in the system storage layout in ESXi 6.x / 7.x. There will be no changes in ESXi 8.0

There is one important change, and that is the consolidation of some partitions in the ESXi 6.x layout into the new ESX-OS Data partition in ESXi 7.0. While the partitions in ESXi 6.x were static, the ESX-OS Data partition can vary in size depending on the size of the boot device.

If you want to use an USB / SD card, it should have a minimum size of 32 GB. I recommend using a high or max endurance microSD card like the SanDisk MAX ENDURANCE microSD-Karte 32GB.

I have used it since ESXi 7, but I decided to reconfigure my home lab and use a persistent 500GB SSD drive as boot device.

And here is where ESX-OS Data dynamic partition size comes into play. The partition can have a maximum size of 138GB.
On a 32 GB drive, ESX-OS Data will be 25 GB, and 55 GB on drives with less or equal 128 GB.

In a home lab there is no need for a 138 GB ESX-OS Data partition. As you can see from this image, the partition size will be pre-allocated, but it does not contain much data.

ESXi 7.0 Update 1c  release adds the boot option systemMediaSize to customize the space used by system-storage during installation and better match the purpose and size of the server. (VMWare KB 81166)

I first tried to edit boot.cfg as described in the KB article, but for some unknown reason this did not work. I recommend to enter the parameter interactive during the installation.

Start the host with the install image and when the ESXi installer window appears, press Shift+O within 5 seconds to edit the boot options.

In the lower left corner you will see something like

runweasel cdromboot

Replace cdromboot with

systemMediaSize=small

for a 55 GB ESX-OS Data partition.

After the installation has finished, you can SSH into the ESXi.

Type ls -ltrh /vmfs/devices/disks/ to get information about all your disks and partitions.

401.8G Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB:8  // datastore
 55.9G Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB:7  // ESX-OS Data
  4.0G Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB:6  // boot-bank 1
  4.0G Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB:5  // boot-bank 0
100.0M Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB:1  // system boot
465.8G Aug 15 04:37 t10.NVMe__Samsung_SSD_970_EVO_500GB    //  

If your persistent SSD drive already contains a VMFS datastore, you must unregister the existing VMs and move them off of the datastore. the ESXi installer needs to repartition the device and this will also delete an existing VMFS datastore.

Although SD cards will still be supported in newer versions of the ESXi with options to move the ESX-OS Data partition off of the SD card to a VMFS datastore, you should consider to put the boot partition(s) on a persistent SSD drive.

The week couldn’t start worse when to come into work on a Monday and find out that one or more of them had self-destructed.


Notes Client 12.0.2 (Danube) – “Workspace_Navigator_Width”

HCL Notes 12 introduced the new Workspace Navigator that replaces the well known tabs at the top to the left sidebar.

You can hide the Workspace Navigator or reduce it’s size to display the tab icons only.

New in HCL Notes 12.0.2 is a notes.ini variable Workspace_Navigator_Width that stores the last size on client shutdown.

As far as I could find out, the default values are

  • 10 (hide/collapse)
  • 55 (tab icons only)
  • 170 (default width )

I prefer the “tab icon” style. The question is: “How can I make the setting persistent?” . If I extend the Workspace Navigator to it’s full size or hide it during a client session, the width would be saved in the notes.ini, and the Workspace Navigator opens with the saved width on next client startup.

I have played with Desktop policy, but found that doing it via policy is not reliable.

panagenda Marvel Client Essentials to the rescue. panagenda Marvel Client Essentials are part of HCL Notes and Domino. Refer to this document to enable the tool in your environment.

Open Marvel Client config and create a new Object -> A5 *.ini & Variables .

Save & close the document. When you now start your Notes Client 12.0.2 the Workspace Navigator will open to the tab icons only state.


Error updating Eclipse IDE to latest build

I am running Eclipse IDE on several machines, physical and virtual. During the past years I have not have any issue when updating to the most recent version.

Today I got an error message, when I tried to upgrade from IDE 09/2021 to IDE 06/2022 on a virtual machine running Windows 11.

I had started eclipse.exe as administrator, but apparently the updater is not able to remove the old binary and replace with a new one.

I could not find any solution but I found a workaround.

  • Run eclipse
  • Rename eclipse exe to eclipse.old
  • Run updates
  • Updates executed successfully

Et voila.


Discovering the unexpected is more important than confirming the known

Without question, this quote by the great statistician George E. P. Box certainly applies to software development in general and Beta testing in particular.

Beta testing is one of the most important phases of the software development lifecycle. Quality, performance, stability, security and reliability are some factors that are achieved by doing beta testing.

Beta testing is the best chance to find bugs and usability issues before a product is fully released. While internal testing can uncover many problems, nothing can truly simulate real users trying to complete real tasks.

HCL has released the 2nd code drop of the upcoming release of (Notes)/Domino “Danube” (12.0.2). Every customer with active maintenance can participate in the Early Access Program. The software is available for download at Flexnet. https://hclsw.co/flexnet

There is a forum where you can provide feedback https://hclsw.co/danube-eap-forum .

Tim Clark (HCL) recently said that “We’ve noticed that not many people are trying out the Domino Early Access drop.”

I do not know what the reasons are. I know for sure that Beta testing can be very time consuming. But you do not have to test all the features from a code drop. Test one feature and comment on everything you see or do not see during your test.

If you do not want to setup a machine just for the Beta testing, maybe Docker is an option for you. Daniel Nashed has done a great job providing Docker images for all kind of Domino server environments. https://opensource.hcltechsw.com/domino-container/

There are no guidelines how to do a Beta test. Also there is no “playbook” that gives step-by-step instructions how to test a feature.

It’s all up to you. Be smart, act stupid. Be a rogue. If you can break a feature, anybody can. Better this happens during Beta testing than in production, right?

If a feature works as described. OK. But I can assure you that in all the years I am participating in Beta programs there is always bits and pieces that needs to be changed to make a feature idiot proofed rock solid, make log messages and console output more understandable or improve useability. This all helps to build a great product. And you can be part of the process.

Always keep in mind that discovering the unexpected is more important than confirming the known.


Domino Early Access Program drop 2 is available

HCL Domino 12.0.2 Early Access Drop 2 is available for download on flexnet.

HCL Domino 12.0.2 Early Access Program drop 2 provides these new features and enhancements:

  • A new tab in the Server document, NIFNSF, allows you to configure moving database view indexes out of databases. Previously, you configured this feature through server notes.ini settings.
  • DAOS Encryption Manager (daosencmgr) now provides the -O [outfile] option to output command results to a specified file. In addition, the DAOS_ENCRYPT_MGR_ENABLE=1 notes.ini setting is no longer required to enable it.
  • Building or rebuilding views take 5-10% less time with Domino 12.0.2.
  • C API OSLoadLibrary changes
    On Windows, if a fully qualified path is not specified for a library to be loaded, the C API OSLoadLibrary no longer searches the path for the library. Instead, by default, this API searches the Notes or Domino executable directory, the Windows System directory, and the Windows directory. You can use notes.ini variables of the format OSSL_<#>= to specify up to five additional locations to search. For example: OSSL_3=”d:\Application\Libraries”. Full details of this this change will be available in the next release of the C API SDK.
  • Smart Server Startup
    A new feature called Smart Server Startup prevents users from connecting to a Domino server until it is fully up and ready to accept user requests. For example, if a server crashes, Smart Server Startup allows users to connect to it only after the server has fully recovered. To see Smart Server Startup activity during server startup, use the notes.ini setting debug_qos=1. To disable the feature, use the notes.ini setting DisableSmartServer=1.

Using AdminQ to process (web) user requests

First of all, AdminQ is not a typo. Administration Quick (AdminQ) is new as of Domino 12.0.1 and can be used to expedite the processing of Administration Process (AdminP) requests that affect the user IDs of web users, for example, HCL Verse users. The users must have IDs in an ID vault.

AdminQ can also be used for Notes users. Add the following entry to the notes.ini on the server.

ADMINQ_WEB_ONLY=0

Find more information on how to customize AdminQ here.

Before AdminQ was available, AdminP requests that affected Notes user IDs required (web) users to use an HCL Notes client to authenticate with a Domino server to complete the requests. With AdminQ, the Notes client authentication is no longer required for the completion of these requests.

AdminQ is a thread spawned by AdminP. It works in conjunction with existing AdminP requests. As of HCL Domino 12.0.2, AdminQ runs automatically on the domain administration server and vault administration servers. The first time AdminQ runs, AdminP creates the Administration Quick Requests database (adminq.nsf) which is used by AdminQ for request processing.

AdminQ comes into play when you perform any of the following tasks for users who have IDs in a vault:

  • Rename users (Available starting with HCL Domino 12.0.1.)
  • Recertify users or Notes users (Available starting with Domino 12.0.2. Requires the 12.0.2 or higher adminq.ntf design.)
  • Roll over the public keys in user ID files. (Available starting with Domino 12.0.2. Requires the 12.0.2 or higher adminq.ntf and idvault.ntf designs.)

Detailed information, how AdminQ processes individual requests can be found for


Domino 12.0.2 EAP CD 1 – ClamAV & ICAP

A word of warning. The described features of Domino 12.0.2 EAP are subject to change in later code drops.
The described configuration of ClamAV & ICAP is NOT intended to be used in production. I take no responsibility for any damage or data loss caused by using the configuration on test or production systems.

A new feature “Virus scanning for message attachments” has been added to Domino 12.0.2 EAP. You can set up HCL Domino to work with any virus scanning server that supports the ICAP protocol to scan attachments in mail messages for viruses. In addition to Domino 12.0.2 , you need a third-party ICAP protocol server to do the virus scanning. Domino has been tested with the products Trend Micro Web Security and McAfee Web Gateway. TLS is required in Domino 12.0.2 GA to connect to the server, but it is disabled by now.

Prerequisites

The installation uses CentOS 8 Stream. The minimum installation was chosen for the software selection. All required packages are installed later via dnf.

For my tests, I have set SELinux to permissive as described here: https://linuxize.com/post/how-to-disable-selinux-on-centos-8/

We need to download and configure some files during the setup. This can be down using VI or any other text editor. I prefer NANO.

dnf -y install nano wget

Next, we install an additional repository

dnf -y install epel-release

Install ClamAV, freshclam and clamd

and install ClamAV and related services.

dnf --enablerepo=epel -y install clamav clamd clamav-update

Run

freshclam

to initialize or update the virus signature databases.

For a scheduled update, we will run freshclam as service. create a new file ( nano will create an empty file, if it does not exists.)

nano /usr/lib/systemd/system/freshclam.service

and add the following content to it

[Unit]
Description = ClamAV Scanner
After = network.target

[Service]
Type = forking
ExecStart = /usr/bin/freshclam -d -c 1
Restart = on-failure
PrivateTmp =true

[Install]
WantedBy=multi-user.target

Save and close the file. Then start the freshclam service and enable it to start on server startup. freshclam will update the signatures once a day.

systemctl start freshclam
systemctl enable freshclam

Created symlink /etc/systemd/system/multi-user.target.wants/freshclam.service → /usr/lib/systemd/system/freshclam.service.

Check the freshclam status.

systemctl status freshclam

● freshclam.service - ClamAV Scanner
   Loaded: loaded (/usr/lib/systemd/system/freshclam.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2022-05-31 07:07:48 CEST; 16s ago
 Main PID: 1809 (freshclam)
    Tasks: 1 (limit: 11344)
   Memory: 2.2M
   CGroup: /system.slice/freshclam.service
           └─1809 /usr/bin/freshclam -d -c 1

May 31 07:07:48 localhost.localdomain systemd[1]: Starting ClamAV Scanner...
May 31 07:07:48 localhost.localdomain systemd[1]: Started ClamAV Scanner.

To configure Clamd edit the /etc/clamd.d/scan.conf

nano /etc/clamd.d/scan.conf

and enable / change the existing values

LogFile /var/log/clamd.scan
PidFile /run/clamd.scan/clamd.pid
TemporaryDirectory /var/tmp
LocalSocket /run/clamd.scan/clamd.sock
LocalSocketGroup root
TCPSocket 3310
User root

then initialize the logfile with

touch /var/log/clamd.scan

Create a new file

nano /etc/tmpfiles.d/clamd.scan.conf

and add the following content

d /run/clamd.scan 0770 root root -

Next, start, enable and get the status of clamd.service

systemctl start clamd@scan
systemctl enable clamd@scan
systemctl status clamd@scan


[root@localhost ~]# systemctl status clamd@scan
● clamd@scan.service - clamd scanner (scan) daemon
   Loaded: loaded (/usr/lib/systemd/system/clamd@.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2022-05-31 06:41:23 CEST; 4s ago
     Docs: man:clamd(8)
           man:clamd.conf(5)
           https://www.clamav.net/documents/
  Process: 1727 ExecStart=/usr/sbin/clamd -c /etc/clamd.d/scan.conf (code=exited, status=0/SUCCESS)
 Main PID: 1728 (clamd)
    Tasks: 2 (limit: 11344)
   Memory: 1.3G
   CGroup: /system.slice/system-clamd.slice/clamd@scan.service
           └─1728 /usr/sbin/clamd -c /etc/clamd.d/scan.conf

Install c-icap

dnf -y install gcc make
curl -L -O http://downloads.sourceforge.net/project/c-icap/c-icap/0.5.x/c_icap-0.5.10.tar.gz
tar zxvf c_icap-0.5.10.tar.gz
cd c_icap-0.5.10

We need to modify the source code to work with Domino 12.0.2 EAP1. this is subject to become obsolete in a future Domino code drop.

Find all occurrencies of “HTTP/1.0” in the source code. The mailscan task in Domino 12.0.2 expects “HTTP/1.1”.

grep -r -e “HTTP/1.0” *

You will get 3 matches in 2 source files.

info.c:    ci_http_response_add_header(req, "HTTP/1.0 200 OK");
utils/c-icap-client.c:    ci_headers_add(headers, "HTTP/1.0 200 OK");
utils/c-icap-client.c:    snprintf(lbuf,1024, "%s %s HTTP/1.0", method, url);

Replace HTTP/1.0 with HTTP/1.1

sed -i 's/HTTP\/1.0/HTTP\/1.1/g' info.c
sed -i 's/HTTP\/1.0/HTTP\/1.1/g' utils/c-icap-client.c

Run the following commands to build and install the binaries

./configure
make
make install
cd

cp /usr/local/etc/c-icap.conf /etc

Create a new file

nano /etc/tmpfiles.d/c-icap.conf

and add the following content

d /var/run/c-icap 0755 root root -

Create the c-icap service. Create a new file

nano /usr/lib/systemd/system/c-icap.service

and add the following content

[Unit]
Description=c-icap service
After=network.target

[Service]
Type=forking
PIDFile=/var/run/c-icap/c-icap.pid
ExecStart=/usr/local/bin/c-icap -f /etc/c-icap.conf
KillMode=process

[Install]
WantedBy=multi-user.target

Now you can start, enable and check the status of the c-icap service

systemctl start c-icap
systemctl enable c-icap

 systemctl status c-icap
● c-icap.service - c-icap service
   Loaded: loaded (/usr/lib/systemd/system/c-icap.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2022-05-31 07:25:30 CEST; 15s ago
 Main PID: 7757 (c-icap)
    Tasks: 37 (limit: 11344)
   Memory: 2.3M
   CGroup: /system.slice/c-icap.service
           ├─7757 /usr/local/bin/c-icap -f /etc/c-icap.conf
           ├─7758 /usr/local/bin/c-icap -f /etc/c-icap.conf
           ├─7759 /usr/local/bin/c-icap -f /etc/c-icap.conf
           └─7760 /usr/local/bin/c-icap -f /etc/c-icap.conf

May 31 07:25:30 localhost.localdomain systemd[1]: Starting c-icap service...
May 31 07:25:30 localhost.localdomain systemd[1]: Started c-icap service.

Install squidclamav

curl -L -O http://downloads.sourceforge.net/project/squidclamav/squidclamav/7.1/squidclamav-7.1.tar.gz

tar zxvf squidclamav-7.1.tar.gz
cd squidclamav-7.1

As with c-icap, we need to modify the source code to work with Domino 12.0.2 EAP1.

grep -r -e "HTTP/1.0" *
src/squidclamav.c:    ci_http_response_add_header(req, "HTTP/1.0 403 Forbidden");
src/squidclamav.c:    ci_http_response_add_header(req, "HTTP/1.0 307 Temporary Redirect");

sed -i 's/HTTP\/1.0/HTTP\/1.1/g' src/squidclamav.c

Build and deploy the binaries

./configure --with-c-icap
make
make install
cd

Edit c-icap configuration

nano /etc/c-icap.conf

and add the squidclamav service after the existing echo service

Service squidclamav squidclamav.so

Create a symlink for the squidclamav configuration file

ln -s /usr/local/etc/squidclamav.conf /etc/squidclamav.conf

Edit /etc/squidclamav.conf and apply the changes

nano /etc/squidclamav.conf

## comment redirect (we don't need it here)
#redirect http://proxy.domain.dom/cgi-bin/clwarn.cgi

## change clamd_local /var/run/clamav/clamd.ctl to
clamd_local /run/clamd.scan/clamd.sock

Restart c-icap

systemctl restart c-icap

Finally, we need to open port 1344 in the firewall

firewall-cmd --zone=public --add-port=1344/tcp --permanent
firewall-cmd --reload

Congratulations! You now have a ICAP server that uses ClamAV to scan your attachments for viruses.

You can now use the ICAP server in your mailscan configuration in Domino 12.0.2. You’ll find information on how to configure mailscan in Domino 12.0.2 here

And last but not least, here is an example of a scanlog for the EICAR virus

I will update this post / write additional information during the Beta phase of Domino 12.0.2.


Error: Index does not exist. (No such file or directory) – UPDATE

This is a follow up article to Error: Index does not exist. (No such file or directory)

Over the past days, I worked with HCL support to find out what causes the issue. With help from the extended support team we finally found the answer.

In my test environment I have an application that stores order data in 250k documents. If the application has no FT index, I can run an agent to find all orders that have a quantity below 30.

	public void sample1(){
		Instant start = null;
		Instant finish = null;
		
		DocumentCollection coll = null;
		DominoQuery dql1 = null;

		try {
			dql1 = order2018.createDominoQuery();
			dql1.setMaxScanDocs(Integer.MAX_VALUE);
			dql1.setMaxScanEntries(Integer.MAX_VALUE);

			String query = "quantity < 30";
			
			start = Instant.now();
			coll = dql1.execute(query, "named_java_rslt_1",true,24);
			finish = Instant.now();
			System.out.println(String.format("%s found %d results in %d msec.", query, coll.getCount(),
					Duration.between(start, finish).toMillis()));
			
			
		} catch (NotesException e) {
			e.printStackTrace();
		} 
	}

When I run the code, I get

[212C:051A-32D0] 06.04.2022 07:33:01   AMgr: Start executing agent 'java.test' in 'orders\dql.nsf'
[212C:051C-30E8] 06.04.2022 07:33:15   Success: overwriting named foundset "named_java_rslt_1"
[212C:051C-30E8] 06.04.2022 07:33:15   Agent Manager: Agent printing: quantity < 30 found 724 results in 14000 msec.
[212C:051A-32D0] 06.04.2022 07:33:15   AMgr: Agent 'java.test' in 'orders\dql.nsf' completed execution

To speed up things a bit, I then created a FT index. I used the new feature in Domino V12 to exclude specific items to keep the index as small as possible. I was only interested in filtering by quantity. So I disabled index creation for all $ items as well as all items except quantity.

The index was created without issues.

[2AAC:0005-2474] FTGIndex: Finished: 0 ms. for [h:\orders\2018.ft] 
[2AAC:0005-2474] 250000 documents added, 0 updated, 0 deleted: 0 text bytes; 8000000 numeric bytes for [h:\orders\2018.ft]
[2AAC:0005-2474] FTGIndex: All Done: 1108 ms for [h:\orders\2018.ft]
[2AAC:0005-2474]  OUT FTGIndex rc = 0 (No error) - for [h:\orders\2018.ft]

When I now run the agent I get

[212C:0520-1FD0] 06.04.2022 07:46:47   AMgr: Start executing agent 'java.test' in 'orders\dql.nsf'
[212C:0522-2328] 06.04.2022 07:46:47   Full Text message: Index does not exist. (No such file or directory)
[212C:0522-2328] 06.04.2022 07:46:47   GTR search error for "h:\orders\2018.ft\ftgi": Index does not exist.: Full text index not found for this database
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error: NotesException: Domino Query execution error:   Full text index not found for this database -  error during planning and tree generation     quantity < 30   (Call hint: FTCalls::FTSearchExt, Core call #0
)   ****************** 
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error:  at lotus.domino.local.DominoQuery.execute(Unknown Source)
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error:  at de.eknori.DQLTest.sample1(DQLTest.java:50)
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error:  at JavaAgent.NotesMain(Unknown Source)
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error:  at lotus.domino.AgentBase.runNotes(Unknown Source)
[212C:0522-2328] 06.04.2022 07:46:47   Agent Manager: Agent  error:  at lotus.domino.NotesThread.run(Unknown Source)
[212C:0520-1FD0] 06.04.2022 07:46:47   AMgr: Agent 'java.test' in 'orders\dql.nsf' completed execution

And here is WHY. There wasn’t a single piece of text indexed. That is because the field quantity is not a “text” field. It is a NUMBER field an that goes into a different index and would not be in FullMain.

I changed the Full Text Index Rules to include at least on TEXT item.

and re-created the index

[2AAC:0005-2474] FTGIndex: Finished: 0 ms. for [h:\orders\2018.ft] 
[2AAC:0005-2474] 250000 documents added, 0 updated, 0 deleted: 1500000 text bytes; 8000000 numeric bytes for [h:\orders\2018.ft]
[2AAC:0005-2474] FTGIndex: All Done: 1087 ms for [h:\orders\2018.ft]
[2AAC:0005-2474]  OUT FTGIndex rc = 0 (No error) - for [h:\orders\2018.ft]

As you can see, we now have a FULLMAIN folder under ftgi.

When I now run my agent, everything works fine

[212C:0526-3348] 06.04.2022 07:52:48   AMgr: Start executing agent 'java.test' in 'orders\dql.nsf'
[212C:0528-0914] 06.04.2022 07:52:48   Success: overwriting named foundset "named_java_rslt_1"
[212C:0528-0914] 06.04.2022 07:52:48   Agent Manager: Agent printing: quantity < 30 found 724 results in 234 msec.
[212C:0526-3348] 06.04.2022 07:52:48   AMgr: Agent 'java.test' in 'orders\dql.nsf' completed execution

Documentation for (Notes)DominoQuery.execute (…) method is wrong

The documentation under https://help.hcltechsw.com/dom_designer/12.0.0/basic/H_EXECUTE_METHOD_NDQ.html#reference_ivd_gz3_cgb and https://help.hcltechsw.com/dom_designer/12.0.0/basic/H_EXECUTE_METHOD_JAVA.html is incomplete, because it does not list all variants for the execute method.

The Lotusscript documentation only shows this syntax

Set doccol = NotesDominoQuery.Execute(Query$, Optional String ResultName, Optional Long ExpireHours)

while the JAVA documentation lists almost all possible syntax variants

DocumentCollection execute(String query) throws NotesException
DocumentCollection execute(String query, String resultname, boolean replace) throws NotesException
DocumentCollection execute(String query, String resultname, boolean replace, int expirehours) throws NotesExceptionn

The correct documentation would be

Set doccol = NotesDominoQuery.Execute(Query$)
Set doccol = NotesDominoQuery.Execute(Query$, Optional String ResultName)
Set doccol = NotesDominoQuery.Execute(Query$, Optional String ResultName, Optional boolean Replace)
Set doccol = NotesDominoQuery.Execute(Query$, Optional String ResultName, Optional boolean Replace, Optional Long ExpireHours)

for Lotusscript, and for Java

DocumentCollection execute(String query) throws NotesException
DocumentCollection execute(String query, String resultname) throws NotesException
DocumentCollection execute(String query, String resultname, boolean replace) throws NotesException
DocumentCollection execute(String query, String resultname, boolean replace, int expirehours) throws NotesException

Be aware that there is NO type check in the Lotusscript for the REPLACE parameter. It is possible to pass i.e. 42 to the method, which would work without any hint that 42 is not a valid value for true or false.


Error: Index does not exist. (No such file or directory)

I recently ran into an issue with the new feature in Domino 12 to exclude fields from full-text search indexes.

You must enable this feature by adding the notes.ini setting FT_DEBUG_DISABLE_DB_RULES=0 to the Domino server AND restart the Domino server.

Navigate to Application Properties -> Full Text Index and select the items to exclude fron the FT index.

You can then delete an existing FT Index and create a new one. The size should be smaller now. So far so good.

If you now do a search either from the Notes Client or progammatically ( LS or Java ) you will get an error.

Y03/26/2022 05:43:54 AM  AMgr: Start executing agent 'qry' in 'ftdemo.nsf'
03/26/2022 05:43:54 AM  Agent Manager: Agent printing: initial query.
03/26/2022 05:43:54 AM  Full Text message: Index does not exist. (No such file or directory)
03/26/2022 05:43:54 AM  GTR search error for "/local/notesdata/ftdemo.ft/ftgi": Index does not exist.: Full text index not found for this database
03/26/2022 05:43:54 AM  Agent Manager: Agent  error: NotesException: Domino Query execution error: 
Full text index not found for this database -  error during planning and tree generation  


idNumber > 20 AND idNumber < 30

	(Call hint: FTSearchExt, Core call #0)


******************

03/26/2022 05:43:54 AM  Agent Manager: Agent  error: 	at lotus.domino.local.DominoQuery.execute(Unknown Source)
03/26/2022 05:43:54 AM  Agent Manager: Agent  error: 	at JavaAgent.NotesMain(JavaAgent.java:35)
03/26/2022 05:43:54 AM  Agent Manager: Agent  error: 	at lotus.domino.AgentBase.runNotes(Unknown Source)
03/26/2022 05:43:54 AM  Agent Manager: Agent  error: 	at lotus.domino.NotesThread.run(Unknown Source)
03/26/2022 05:43:54 AM  AMgr: Agent 'qry' in 'ftdemo.nsf' completed execution

The issue is reproducible on Windows and Linux. I have opened a support case with HCL.

If you disable the feature, restart the server and recreate the index, everthing works good.