Rebuilding a Notes Mail Inbox

Your Inbox in your mail file has become corrupt for whatever reason. Because the Inbox is a folder, it does not use selection formulas to give a collection of documents. It is built by the router depositing messages there. Once the folder is destroyed or replaced, the collection is lost with it. After replacing it with a new one, only new documents will be deposited in it from that point on.

Below is a script that can be used to repopulate your Inbox with the older mail messages that have not been currently filed in folders. The script can be placed in a button and mailed to the users who need it.

Read More


GIF und BMP mit Lotus Script erstellen

Guido Purper hat auf OpenNTF eine Lotus Script Klasse veröffentlicht, mit der es möglich ist, on the fly GIF und BMP Dateien zu erzeugen.

“I have developed this class to present statistical data in visual form (as graphs) and send them to some people automatically.
You can create 256-color images on-the-fly from within Notes, attach or embedd the images to HTML/MIME documents and send them to other people. This is not a “Paint” application, there is no way of interaction. This is a class to create images by Lotus script e.g. from an agent.” (Guido Purper, Januar 2005)

Damit lassen sich aus den Dokumenten einer Datenbank Statistiken erstellen, plattformunanbhängig und ohne zusätzliche Programme. Es kommt pures Lotus Script zum Einsatz. Durch die Verwendung spezieller Lotus Script Befehle ist die Klasse nur unter ND 6 verwendbar.

OK, das ist noch nicht so sonderlich schön geworden, aber mit ein bisschen Ã?bung lassen sich durchaus beeindruckende Ergebnisse erzielen.


Excel Datei ohne Excel erstellen

Programme zum Exportieren von Daten aus einer Lotus Notes Anwendung heraus gibt es viele. Alle diese Programme setzen voraus, daÃ? Excel auf dem Rechner, der die Exportdatei erzeugt auch installiert ist. Was macht man aber, wenn auf dem Rechner Excel nicht installiert ist oder der Export gar auf einem Server im Hintergrund laufen soll ? Was wenn die erzeugte Datei evtl. auch noch von älteren Versionen gelesen werden soll ?
Ein Format, welches Excel schon seit der Version 2.1 verwendet und welches auch noch mit Excel 2003 gelesen und verarbeitet werden kann ist BIFF2.1 ( Binary File Format )

Read More


@Command([ToolsUserLogoff]) in Lotus Script

Mit Hilfe der Windows API kann der Befehl @Command([ToolsUserLogoff]) in Lotus Script simuliert werden.

VK_F5 = &H74
Const KEYEVENTF_KEYDOWN = &H0000
Const KEYEVENTF_KEYUP = &H0002

Declare Sub WIN32_KeyBoardEvent Lib "User32" Alias "keybd_event" ( Byval bVirtualKey As Integer , Byval bScanCode As Integer , dwFlags As Long , dwExtraInfo As Long )
Sub Logoff ( )
  Dim ModuleName As String
  ModuleName = {Logoff}
  On Error Goto ErrorHandler

  WIN32_KeyBoardEvent VK_F5 , 0 , KEYEVENTF_KEYDOWN , 0
  WIN32_KeyBoardEvent VK_F5 , 0 , KEYEVENTF_KEYUP , 0
  Exit Sub

  ErrorHandler:
  Select Case fnErrorHandler ( Error$ , Err , Erl , ModuleName )
    Case 0
      Exit Sub
    Case 1
      Resume Next
    Case Else
      Resume Next
  End Select
End Sub

Function fnErrorHandler ( strErrorText As String , lngErrorNumber As Long , lngErrorLine As Long , strModuleName As String ) As Integer
Print ( {ERROR: } + strErrorText + { (Nr.: } + Cstr (lngErrorNumber ) + {, Line: } + Cstr (lngErrorLine ) + {, Module: } + strModuleName + {)} )
fnErrorHandler = 1
End Function

Und zum Testen folgender Aufruf

Sub Click(Source As Button)
  Call Logoff
End Sub 

Enumerating Local And Network Drives

Is there a way that I can return all available local drive letters ? Yes, there is a way !

Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (Byval nBufferLength As Long, Byval lpBuffer As String) As Long
Function GetDrives() As String
  Dim tmp As String
  Dim iCount As Integer
  Dim strDrives As String

  strDrives = Space$(64)
  Call GetLogicalDriveStrings(Len(strDrives), strDrives)
       For iCount = 1 To Len(strDrives) Step 4
           tmp = tmp & " " + Mid$(strDrives, iCount, 1)
      Next iCount

     GetDrives = Trim(tmp)
End Function
Sub Click(Source As Button)
    Msgbox getdrives
End Sub

DatabaseProperties Class

The DatabaseProperties class has been created to manage Notes databases in small to enterprise-wide domains using LotusScript and C API to set most Database settings on R5/R6 databases that you can set via client notes but pou don’t manage via LotusScript directly.

Its code has been built/expanded from the various Lotus Script/C API contributions over the years in the forums by many authors such as Normunds Kalnberzins and Rod Whitely as well as the dbdesign stuff by Damien Katz (and expanded dbdesign by Josh Jore).

This class is an extension of the “dbdesign” and a reorganization of the function that you can get in “R5 Database Manager” and my improvment. For the DBDesign a i made a fix in the method that update the document thant contain Template Name/Design Name/Category. Now the string store in the notes document does not contain a garbage Characters.


Determine Drive Types and Next Available Drive Letter

When dealing with drive types and letters it is nice to have a simple function to give you that information. The function shown below will cycle through each of the valid drives on the system running the program and tell you what each type is. Once it is finished, it tells you what the next available drive letter is. In dealing with network applications, it is sometimes necessary to add a drive letter for a new connection.

The first thing you will need is an API declaration. This declaration looks like the following:

Declare Function GetDriveType  Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String)As Long

The next thing you will need is the function to actually perform the work for you. The function looks like the following:

Function FreeDrive() As String
	Dim DriveNum As String    'To cycle through drive letters in order
	Dim DriveType As Long     'To hold the type of drive it is
	DriveNum = 64             'Prime the variable to be used in the loop
	 Do
	 	DriveNum = DriveNum + 1   ' start at drive zero.
	 	DriveType = GetDriveType(Chr$(DriveNum) & ":")
	 		If DriveType = 1 And DriveNum > 67 Then Exit Do
	 			Select Case DriveType
	 				Case 0: MsgBox Chr$(DriveNum) + ": is An Unknown type"
	 				Case 1: MsgBox Chr$(DriveNum) + ": Does Not Exist"
	 				Case 2: MsgBox Chr$(DriveNum) + ": is a Removable Drive"
	 				Case 3: MsgBox Chr$(DriveNum) + ": is a Fixed Drive"
	 				Case 4: MsgBox Chr$(DriveNum) + ": is a Remote Drive"
	 				Case 5: MsgBox Chr$(DriveNum) + ": is a CD-ROM Drive"
	 				Case 6: MsgBox Chr$(DriveNum) + ": is a RAM Drive"
	 			End Select
	 Loop

	 FreeDrive = Chr$(DriveNum) + ":"  'Return the next available drive letter
	 End Function

Finally, you need to place the code in an event procedure or other routine to call the FreeDrive Function. In this case, we are simply calling the function by placing the return value into a message box.

Sub Click(Source As Button)
	Msgbox "Next Available Drive letter is " & FreeDrive()
End Sub

Distance Between 2 Points On Earth

Wie weit ist es von Mettmann nach Düsseldorf, oder von Mettmann nach Frankfurt ? Früher gab es mal so kleine Geräte, mit denen man in einer Karte die Entfernung zwischen zwei Städten dadurch bestimmen konnte, daÃ? man mit diesem Gerät die Strecke zwischen Start- und Zielort entlangfuhr. Die Entfernung lieÃ? sich dann auf einer analogen Scala ablesen; vorausgesetzt, man hatte den MaÃ?stab der verwendeten Karte richtig eingestellt.
Heute in digitalen Zeitalter stehen dazu weit bessere, genauere Methoden zur Verfügung. GPS z.B. ist eine davon. Viele Autos ( meines nicht ) haben bereits ein solches System eingebaut. Man kann Start- und Endpunkt eingeben und erfährt sogleich neben anderen Informationen die exakte zurückzulegende Strecke; auf den Meter genau (?).
Wie aber kann man auch Lotus Notes dazu bewegen, die Entfernung zwischen zwei Staedten zu berechnen ?
Im deutschen Notes Forum wurde diese Frage gestellt. Allerdings wurde hier nach einer Funktion gefragt, die z.B. Filialen in einem vorgegebenen Umkreis zum Standort anzeigt / auflistet.
Ich möchte mich hier zunächst einmal darauf beschränken, eine Funktion vorzustellen, die es ermöglicht, auf Grundlage vorgegebenen Ortskoordinaten die Entfernung zwischen zwei Orten zu berechnen.

die Originalformel von http://www.gumo.de/ ( Visual Basic-Funktion zur Berechnung der Entfernung zwischen zwei Punkten auf der Erdoberfläche ) habe ich nach Lotus Script portiert.

Die Koordinaten müssen folgendermaÃ?en aufgebaut sein:

Mettmann 06E59 51N15

das bedeutet Mettmann liegt 51°15’00″Nord und 06°59’00″Ost.
Die Koordinaten habe ich einer Auflistung entnommen, die unter http://www.themamundi.de/aws/tabel/tbmain.htm zu finden ist. Es werden gröÃ?tenteils die Sekunden bei den Koordinaten weggelassen; die Formel kann aber auch mit Koordinaten der Form 06E5922 51N1501 rechnen.

Hier ein Beispiel zum Funktionsaufruf.

Sub Click(Source As Button)
        'Mettmann    06E59      51N15
        'Düsseldorf   06E47      51N14
	Msgbox  dblDistanceBetween2PointsOnEarth ( "51N15" , "06E59" , "51N14 " , "06E47" )
End Sub
Function dblDistanceBetween2PointsOnEarth(  c1N As String, c1E As String, c2N As String, c2E As String ) As Double

'Die Funktion liefert die Entfernung zweier Punkte auf der Erdoberfl?che in km.
'Das Verfahren ber?cksichtigt die Erdabplattung und ist auch für sehr kleine Entfernungen genau.
'Keine Ber?cksichtigung der Höhe ?ber N.N.!
'Quelle: Jean Meeus - Astronomische Algorithmen (Auflage 1992, Verlag Johann Ambrosius Barth), Seite 93f, 118ff    '
	Dim phi1_rad As Double
	Dim lambda1_rad 	As Double
	Dim phi2_rad  As Double
	Dim lambda2_rad 	As Double
	Dim F 	As Double
	Dim sinF2 As Double
	Dim cosF2 As Double
	Dim G As Double
	Dim sinG2 As Double
	Dim cosG2 As Double
	Dim dl As Double
	Dim s 	As Double
	Dim C As Double
	Dim om As Double
	Dim R  As Double
	Dim cosD As Double
	Dim D As Double
	Dim H1  As Double
	Dim H2 As Double
	Dim DEG As String
	Dim MMSS As String
	'Needed constants Const
	Const RADIAN = Pi / 180
	' mittlerer Erdradius in km
	Const MEAN_RADIUS = 6371.299
	' Abplattung der Erde
	Const FLATTENING_FACTOR = 1 / 298.257
	' Ã?quatoradius in km
	Const EQUATOR_RADIUS = 6378.14

	'Convert to radians
	MMSS= atWord (c1N,"N",2)
	DEG = atWord (c1N,"N",1)

	If Len (MMSS) = 4 Then
		phi1_rad = (DEG + (Left$(MMSS,2)  / 60) + (Right$(MMSS,2)  / 3600)) * RADIAN
	Else
		phi1_rad = (DEG + (MMSS  / 60)) *RADIAN
	End If

	MMSS= atWord (c1E,"E",2)
	DEG = atWord (c1E,"E",1)
	If Len (MMSS) = 4 Then
		lambda1_rad = (DEG + (Left$(MMSS,2)  / 60) + (Right$(MMSS,2)  / 3600)) * RADIAN
	Else
		lambda1_rad = (DEG + (MMSS  / 60)) * RADIAN
	End If

	MMSS= atWord (c2E,"E",2)
	DEG = atWord (c2E,"E",1)
	If Len (MMSS) = 4 Then
		lambda2_rad = (DEG + (Left$(MMSS,2)  / 60) + (Right$(MMSS,2)  / 3600)) * RADIAN
	Else
		lambda2_rad = (DEG + (MMSS  / 60)) * RADIAN
	End If

	MMSS= atWord (c2N,"N",2)
	DEG = atWord (c2N,"N",1)
	If Len (MMSS) = 4 Then
		phi2_rad = (DEG + (Left$(MMSS,2)  / 60) + (Right$(MMSS,2)  / 3600)) * RADIAN
	Else
		phi2_rad = (DEG + (MMSS  / 60)) * RADIAN
	End If

	'Check on precise calculation
	cosD = Sin(phi1_rad) * Sin(phi2_rad) + Cos(phi1_rad) * Cos(phi2_rad) * Cos(lambda1_rad - lambda2_rad)
	If cosD < 0.999995 Then'Distance is long
		F = (phi1_rad + phi2_rad) / 2
		sinF2 = (Sin(F)) ^ 2
		cosF2 = (Cos(F)) ^ 2
		G = (phi1_rad - phi2_rad) / 2
		sinG2 = (Sin(G)) ^ 2
		cosG2 = (Cos(G)) ^ 2
		dl = (lambda1_rad - lambda2_rad) / 2
		s = sinG2 * (Cos(dl)) ^ 2 + cosF2 * (Sin(dl)) ^ 2
		C = cosG2 * (Cos(dl)) ^ 2 + sinF2 * (Sin(dl)) ^ 2
		om = Atn(Sqr(s / C))
		R = Sqr(s * C) / om
		H1 = (3 * R - 1) / (2 * C)
		H2 = (3 * R + 1) / (2 * s)
		dblDistanceBetween2PointsOnEarth = 2 * om * EQUATOR_RADIUS *_
		(1+ FLATTENING_FACTOR * H1 * sinF2 * cosG2  - FLATTENING_FACTOR * H2 * cosF2 * sinG2 )
	Else          'Distance is short
		dblDistanceBetween2PointsOnEarth = Sqr(((lambda2_rad - lambda1_rad) *_
		Cos((phi1_rad + phi2_rad) / 2)) ^ 2 + (phi2_rad - phi1_rad) ^ 2) * MEAN_RADIUS
	End If
End Function

Diese Formel gilt für Erdkoordinaten auf der nördlichen Erdhalbkugel und Werte die östlich von Greenwich liegen. Also Erdkoordinaten mit einem N und O. Die gleiche Formel kann man auch für alle anderen Koordianten benutzen, man muÃ? nur bei Süd- und Westwerten jeweils ein Minus davorstellen. Also S und W Werte mit -1 multiplizieren! Zum Splitten der Koordinatendaten wird die Funktion atWord verwendet. atWord ist das Lotus Script Ã?quivalent zu @Word

Function atWord ( sourceString As String, separator As String, number As Integer ) As String
	searchString$=SourceString & separator
' add one separator to catch also the last substring
	For i% = 1 To number
		pos%=Instr(searchString$, separator)
		If pos%=0 Then
			Exit For
			substring$=Left(searchString$,pos%-1)
			searchString$=Mid(searchString$, pos%+1)
		Next
		If pos% > 0 Then
			atWord=substring$
		Else
			atWord=""
		End If
End Function

DOWNLOAD


Dateihandling

Jeder kennt das Problem: Die User in einem Unternehmen erstellen verschiedenartige Dokumente, die im Filesystem gespeichert werden. Bedingt durch Sicherheitsrichtlinien haben nicht alle Mitarbeiter die gleichen Zugriffsrechte.
In den meisten Unternehmungen gibt es noch nicht einmal ein Transferlaufwerk, auf das ALLE Mitarbeiter Lese- und Schreibberechtigung haben. Daher wird vielfach der Dateiaustausch über das Medium email bewerkstelligt. Je nach den gewählten Benutzereinstellungen entstehen durch diese Methode Duplikate ( Original auf dem Filesystem, Kopie im Ordner “Gesendet” und noch eine Kopie beim Empfänger ).
Angeregt durch den Thread “Dateiauswahl in Mailmaske” im deutschen Notes Forum habe ich das Thema aufgegriffen und möchte hier meinen Lösungsvorschlag vorstellen.

Einen Lösungsansatz findet man z.B. in der Sandbox. Allerdings werden die Dateien beim Klicken auf die erzeugten Links nicht in der zugehörenden Applikation sondern im Browser geöffnet. Im ungünstigsten Fall wird statt des Dateiinhaltes lediglich der Downloaddialog angezeigt. Da drehen wir uns dann im Kreis, denn ein erneutes Speichern der Datei wollen wir ja gerade vermeiden.

Selbstverst?ndlich wäre es schön, wenn ein Link zu einer Datei ebenso wie die Links in diesem Beitrag im Kontext des Textes erzeugt werden k?nnen. Dazu müsste man dann die Notes API verwenden. Erste Versuche haben aber gezeigt, dass die Verwendung der Api in diesem Falle alles Andere als trivial ist.

Daher habe ich mir einen anderen Ansatz überlegt. Zwar wird auch hier in einer Funktion Gebrauch von der Windows API gemacht, ob die API aber unbedingt notwendig ist, ist im Einzelfall zu prüfen.

Die vorgeschlagene Lösung basiert auf einer Teilmaske; somit kann die gewünschte Funktionalität in jede beliebige Datenbank eingebaut werden. Die Teilmaske enthält alle erforderlichen Elemente. Zusätzliche Script Bibliotheken oder Agenten sind nicht erforderlich.

In der Teilmaske sind folgende Funktionen enthalten

  • Hinzufügen einer Datei ( Add File )
  • Enfernen einer Datei ( Remove File )
  • Entfernen aller Dateien ( Remove All )
  • Starten einer Datei ( Open File )

Die Auswahl der Dateien erfolgt über einen Dialog, wie er in Windows Anwendungen üblich ist. Notes stellt eine API Funktion zur Verfügung, die in Lotus Script verwendet werden kann.

Declare Function NEMGetFile Lib "nnotesws" (wUnk As Integer, Byval szFileName As String, Byval szFilter As String, Byval szTitle As String ) As Integer
Sub Click(Source As Button)
	Dim workspace As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Set uidoc = workspace.CurrentDocument
	Dim szFileName As String*256
	Dim szTitle As String
	Dim szFilter As String
	Dim session As New NotesSession
	szFilename = Chr(0)
	szTitle = session.Commonusername & ", select your database NOW"
	szFilter = "MS Word Documents|*.doc|Notes Databases|*.NSF|Notes Templates|*.NTF|Programs|*.EXE|All Files|*.*|"
	If NEMGetFile( 0, szFileName, szFilter, szTitle) <> 0 Then
		szFileName = szFileName & |"|
		Call uidoc.FieldAppendText ( "fList",  "," + GetShortFileName (szFileName) + "," )
	End If
End Sub

In einem früheren Code ( reattach ) habe ich beobachtet, daÃ? Notes manchmal Probleme bei langen Dateinamen hat. Diese Probleme treten besonders dann auf, wenn der Pfad oder die Datei selber Leerzeichen enthält. Daher habe ich die Function GetShortFileName eingebaut. Die Funktion bedient sich der Windows API

Declare Function GetShortPathName Lib "kernel32" Alias"GetShortPathNameA" (_
Byval lpszLongPath As String,Byval lpszShortPath As String, Byval cchBuffer As Long) As Long
Function GetShortFileName ( fileName As String ) As String
	Dim sBuffer As String , lLen As Long
	sBuffer = Space$ ( 512 )
	lLen = GetShortPathName  ( fileName , sBuffer , Len ( sBuffer ) )
	GetShortFileName = Left$(sBuffer, lLen )
End Function

Damit ist eigentlich auch schon der GroÃ?teil der Arbeit getan; ab hier geht es wieder ohne Lotus Script weiter.

btnRemoveFile

 _Names :=  fList ;
_Del :=  @Prompt([OkCancelList]:[NoSort] ;"Dateiauswahl";"Bitte wählen Sie die zu löschende Datei aus!"; "" ; _Names ) ;
@If( _Del != 1; "" ; @Return( "" ) ) ;
_Elems := @Elements( _Names ) ;
_Pos := @Member( _Del ; _Names ) ;
FIELD fList := @Trim( @If( _Pos = 1 ; "" ; @Subset( fList ; _Pos - 1 ) )  : @If( _Pos = _Elems ; "" ; @Subset( fList ; - ( _Elems - _Pos )  ) ) ) ;
@Command([ViewRefreshFields])

btnRemoveAll

FIELD fList:=@DeleteField;
@True

Damit wären wir schon am Ende; war doch gar nicht so schwer, oder? Ich bin mir darüber im Klaren, dass dies nur eine einfache Lösung ist. Selbstverständlich m?ssen die Empfänger einer Mail mit Dateilinks auch Zugriff auf die Dateien haben. Anwender, die ohne Netzanbindung arbeiten können nicht auf die Links zugreifen. Es sollte auch keine allumfassende Lösung vorgestellt werden. Es handelt sich, wie eingangs erwähnt lediglich um einen Ansatz. Möglicherweise ist dem Einen oder Anderen damit schon geholfen. Wenn dem so ist, würde ich mich ?ber ein kurzes Feedback freuen.

DOWNLOAD


PING in LotusScript

Die Klasse PING enhält die Funktion Ping(), der die zu überpr?fende Adresse als Zeichenkette in der Form “127.0.0.1” übergeben wird. Ist der Ping erfolgreich wird true zurückgegeben,ansonsten false.

Die Konstante TIMEOUT gibt an, wie viele Millisekunden ( DEFAULT = 500 ms ) die Funktion versuchen soll, den Zielrechner zu erreichen. Zum Testen der Funktion erstellen sie einen Button und kopieren sie den folgenden Code in den Click Event der Schaltfläche

Read More


Lotus Script Klasse “Systeminformationen”

Lotus Script Klasse mit folgenden Funktionen:

    kleine/ grosse Schriftarten installiert
    Ist eine Soundkarte installiert
    Anzahl Farben
    Tastatur Typ
    Anzahl Funktionstasten
    Hostname
    IP Adresse des Host
    aktuelle Bildschirmaufloesung
    CPU Taktfrequenz
    Anzahl Processoren
    Prozessor Typ
    Prozessor Build Level
    Prozessor Revision
    Betriebssystem
    Windows Systemverzeichnis
    Notes Verzeichnis
    Welche COM Ports sind verfuegbar
    Dateisystem, Label und
    Seriennummer der Festplatte
    Neustart von Windows ( auch Windows 2000 !!
    LockWorkstation
    Internet – Verbindungsstatus

DOWNLOAD