Personal Blog of Thomas Hampel - Creative Mythbusting in Development and Collaboration

Query results for : Code

Improving the Mail Template 9.0.1FP9 - Manage Return Receipts according to RFC 2298- 19 September 2017 - (0) Comments

Thomas Hampel
 19 September 2017

According to RFC 2298 http://www.ietf.org/rfc/rfc2298.txt it is recommended to show a dialog box where the recipient of a mail can decide weather or not a return receipt shall be sent back to the originator of the mail. This behavior is not currently part of the Standard IBM Mail template.

To add this feature you have to modify the following design elements:
  • Form “Memo”, Event "QueryOpenDocument", added the code shown below
  • Form “Reply”, Event "QueryOpenDocument", added the code shown below
  • Form “ReplyWithHistory”, Event "QueryOpenDocument", added the code shown below

Insert this code at the end of the QueryOpenDocument event.

Set doc = Source.document
If Source.isNewDoc Then
        '# don' t do anything, as this is a new document
Else
        If doc.GetItemValue("ReturnReceipt")(0) = "1"  And doc.HasItem ("DeliveredDate") Then
                If MessageBox ("The sender of this message has asked to be notified when you read this message." & Chr(13) & "Do you wish to notify the sender?", 36, "Send Return Receipt?") = 7 Then
                        Call doc.ReplaceItemValue ("ReturnReceipt", "0")
                        Call doc.Save(True, False, true)
                End if
        End If
End If


Reference:
http://www.ibm.com/developerworks/lotus/library/ls-BlockRetRec/index.html

Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option- 16 February 2017 - (0) Comments

Thomas Hampel
 16 February 2017

This is the fourth post our of a series of blog posts describing how to move from password based to seamless authentication.
In Level 3 - SPNEGO I have explained how to configure SPNEGO authentication for providing seamless authentication. A drawback of this method was that users can only log in with the current OS user, switching to a different context was not possible. In this level I am providing a solution to switch the user without switching the OS user.

Level 3 - SPNEGO with fallback option

The SPNEGO configuration from Level 3 - SPNEGO alone will automatically log in the user with his OS credentials. There are cases where the machine is used by multiple users which -for whatever reason- share the same OS user, or when the OS user is not member of the ActiveDirectory, or the current OS user does'nt have the required Notes name listed in LDAP..... However, think of kiosk machines, etc. where the OS user has little to no access rights in corporate applications. So we would like to provide them with an option to authenticate with credentials other than the OS user.

Pros and Cons

+ Seamless authentication for browser clients on Windows
+ Ability to switch user without logging off/on from OS
- It's Windows only
- Does'nt work for Traveler and Sametime

Prerequisites
  • You have successfully completed Level 3 - SPNEGO
  • You have (at least) two IP addresses on your Domino server or have at least two Domino servers in your environment

Idea and Concept

Main idea is to handle to handle login and not authenticated errors and redirect user sessions to a fallback authentication page hosted on a Domino server that does not use SPNEGO.
This brief workflow diagram describes how its done:
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option
The first part of the authentication flow is shown in the "Conceptual Overview" graphic in this article where the sequence is as follows
1
The user is trying to access a protected resource (e.g. “serviceurl.company.com”) by using a web browser. The browser is establishing an SSL session on Port 443 and sends HTTP GET / Post request.
2
Domino returns HTTP401 WWW-Authenticate:Negotiate
3
The Client sends HTTP GET / Post request via SSL with an authorization SPNEGO Token
4
Domino verifies if the token format received from the Browser is SPNEGO
5
Domino validates the ticket against Kerberos Domain Controller to authenticate the user
6
With the Kerberos name is returned, Domino will make an outbound call in order to find the Domino distinguished name (e.g. attribute “mailNickname” ) within ActiveDirectory by looking up the Kerberos name. For successful authentication the result is a Notes User name which will be used for this session, continue with 7a. For unsuccessful authentication the result is HTTP Not Authorized, continue with 7b
7a
Domino returns an LTPAToken to the client and proceeds to the requested resource by verifying access rights in the ACL. At this point the user is authenticated and the process will end here.
7b
Domino returns HTTP403 Not Authorized, The user will be redirected to a custom logon page for non-SPNEGO users, continue with step #9 in the next chapter.



For a concept with a fallback option you'll need at least two internet sites or two Domino servers with a different configuration for each.
Users trying to access a protected resource (e.g. application) that they are not authorized to use, will get a custom error page returned with a javascript that will redirect to a non-SPNEGO site.
This graphic shows two Domino servers where one is using internet sites and one is using an old style web configuration - both use a web SSO configuration document called "LtpaToken".
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option
8
The user was trying to access a protected resource (e.g. “authenticationURL.company.com”) by using a web browser. The browser is establishing an SSL session on Port 443 and sends HTTP GET / Post request.

Internally Domino is returning HTTP 403 – Not Authorized, which causes Domino to check if a custom error handler has been configured for the requested URL.

9
Domino returns the custom error page configured for this URL. If no custom error handler has been configured only the browser default error message for HTTP403 Not Authorized will be displayed.
10
The browser will render the custom error page, which contains a JavaScript to redirect the client to a fallback authentication page.



Depending on the type of resource, a custom login page will be displayed, either the iNotes login page or a custom one.
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option

More details:
11
The user is trying to access a protected resource by using a web browser.The browser is establishing an SSL session on Port 443 and sends HTTP GET / Post request
12
Domino returns a username password dialog box which has been configured for this URL. The layout of this form depends on the URL requested. See Domcfg.nsf
13
The user is entering his ActiveDirectory- or DominoHTTP username / password.Credentials are sent via SSL to the server for verification.
14
Domino is verifying credentials against the Directories configured in its directory assitence database. Multiple directories can be specified, Domino will process all of them.

The connection to an Active Directory server is established via LDAP / SSL using its own credentials configured in the directory assistance database.

15
For successfully authenticated users, the AD user object is returned to Domino. Domino will read the attribute “mailNickname” from the user object and will use this as Notes user name for the user session.
16
Domino returns an LTPAToken to the client and will verify access rights in the ACL of the requested resource or will redirect the user back to the URL he wanted to access in the beginning
17
The browser will receive the LTPAToken in form of a cookie which is valid for the DNS Domain defined in the WebSSO key. At this point the user is authenticated. The browser can now present this cookie to any server which is member of this DNS domain to identify himself.



How to...

Assuming LDAP authentication + SPNEGO have been configured already + domcfg.nsf exists, here is what to do:

1. Create a Web SSO Configuration for SPNEGO Enabled

In this example I'm using "DominoSPNEGOEnabled" as the configuration name.
Organization yourCompany
DNS Domain .yourdomain.com
Map names in LTPA tokens Enabled
Require SSL protected communication (HTTPS) Disabled
Restrict use of the SSO token to HTTP/HTTPS Disabled
Configuration Name DominoSPNEGOEnabled
Participating Server Names List of all servers in the Domain
Windows single sign-on integration (if available) Enabled
Token Expiration 180 minutes



2. Create a Web SSO Configuration for SPNEGO Disabled

Copy and paste the document for the SPNEGO enabled configuration, and change the following elements:
  • Configuration Name: DominoSPNEGODisabled
  • Windows single sign-on integration (if available): Disabled
Key is to have the same WebSSO key for both configurations, which is a value computed when creating a new document. So make sure to copy/paste the existing Web SSO Configuration document to obtain the same key. In case the key will be changed, make sure to update the document which you copied accordingly.

3. Create Internet Site Documents

Prerequisite for the configuration is to use internet site documents for Domino servers providing HTTP services.
Each of the Internet Sites configured should be configured to use the Web SSO configuration created before
  • Web SSO Configuration: DominoSPNEGOEnabled
    This is the name of the Web SSO Key created in the previous step.
  • Force login on SSL: Yes
Then create another Internet Site document to be used as authentication URL, which will be using the DominoSPNEGODisabled

Note that you should use an SSL certificate for each domain. When both internet site documents are located on the same server, you'll need one IP addresses for each domain to properly handle the SSL certificate binding
If you only have one IP address per server, you need two servers where one is using internet sites and one is using web configurations.
Hint: To use the same SSO Key for both types you need to copy/paste the WebSSO document and remove (or add) the company field in one of them

4. Create a Custom Login Form Mapping

This will provide a nice looking a new A username/password dialog box is displayed when SPNEGO can not be used,as alternative for authenticating via username / password.
This form can be customized according to your needs, I'm using the iNotes login form here
Target Database : Domcfg.nsf
Target Form : iNotesLoginForm

5. Create a Custom ‘Not Authorized’ Error Form

This form will be displayed to users who have successfully authenticated against Domino/Active Directory but are not allowed to access the application.
Open the file “domcfg.nsf” in your Domino Designer client, and create a new form called “NotAuthorized”
  • Set the Window Title to “Not Authorized”
  • Set the HTML Head Content to client/formula:
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option
  • Add one new field “database” of type text/computed for display
    Formula : @UrlQueryString( "database" )
  • Add some HTML code to the body of the form indicating that there is no access to this resource, and mark it as passthru-html using the menu “Text\Passthru-HTML”
    Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option
  • Add the following HTML code to the body of the form, note it contains two computed text blocks
    Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option

    where the formula for is : @Name([CN];@UserName)
    and the formula for is : @LowerCase(@RightBack( @LeftBack( @UpperCase(@UrlQueryString( "database" ));".NSF"); "/")) + ".nsf"
  • Enable the flag “Available to Public Access users” in the form properties
    Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option

6. Create a Custom Redirect Form

This form is used for redirecting anonymous users to a different site than users who have authenticated already.
Open the file “domcfg.nsf” in your Domino Designer client, and create a new form called “AnonymousRedirect”
  • Set the Window Title to “Redirecting”
  • Add the following HTML code to the body of the form, and mark it as passthru-html using the menu “Text\Passthru-HTML”
    Where 'Authentication URL' is the defined DNS name of the Domino server which is hosting the nonSPNEGO Web SSO Configuration.
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option
  • Type the (non-passthru-html) text “Redirecting…” into the body of the form.
    This text will be displayed to users while the redirect is in progress.
  • Add one new field “RedirectTo” of type text/editable with a default value of “/” at the bottom of the form

Note: There are different options to redirect users, this method is based on a simple JavaScript which will redirect anonymous users to another place than users who have already authenticated but are not authorized to access the resource.

7. Custom Error Handler

Within “domcfg.nsf”, a custom error handler for authorization failures will need to be created in order to redirect users who can not participate in SPNEGO.
Use the view “Error and Response Mapping” and click the "Add Mapping" button.
Applies To  : All Web Sites/Entire Server
For Authentication failures and for Authorization failures, use the same mapping:
Target Database : Domcfg.nsf
Target Form : AnonymousRedirect
Image:Domino SingleSignOn - Level 4 - Seamless Kerberos authentication via SPNEGO with fallback option

Result:

Seamless authentication works fine as before but in addition you get propper error handling.
If users are not authenticated, or not allowed to access the resource, they will be redirected to a page that will allow them to log in as different user.

Troubleshooting
  • The following Notes.ini variables will help to analyze problems:
  • Technote 1394592 - Troubleshooting Windows single sign-on for Web clients (SPNEGO)
  • Make sure the LDAP attribute used for name mapping contains the Notes Name of the user in DN format.
    This is the fully canonical name but slash “/” replaced by a comma “,”
    e.g. for “Peter Mueller/Department/Org” this would be: “CN=Peter Mueller,OU=Department,O=Org”
  • Use the developer tools in your internet browser to display your cookies. You should have a LtpaToken Cookie set.
  • Last but not least: drop a mail or call the author of this blog post.

Domino SingleSignOn - Level 2 - Self Service Password Reset Application - 14 February 2017 - (0) Comments

Thomas Hampel
 14 February 2017

Based on a recent discussion with a customer it seems there still is not enough information on how to simplify authentication for Notes/Domino users.
This is the second post our of a series of blog posts describing how to move from password based to seamless authentication.
Once you have established LDAP Authentication you can approach the next stage:

Level 2 - Self Service Password Reset Application

Combined with a Self Service Password Request HTTP application (or this fancy one ) users can reset Notes password without the help of an administrator just by using a web browser.
Users must be authenticated in order to reset their own password, but due to the configuration done in level 1 they can use Active Directory credentials to log in.
Once authenitcated a user can just define a new password which is applied immediately in the IDVault. And just seconds later the password can be used to log into the Notes Client.
Image:Domino SingleSignOn - Level 2 - Self Service Password Reset Application

Pros and Cons

+ Lost/forgotten passwords on a monday morning are no longer your problem. Users can handle this problem alone.
+ You don't need to distribute NotesID passwords for newly created users.
- There still is a NotesID password to remember
- There still is a password prompt every time you start the Notes client and/or every time you open an encrypted mail in iNotes
- The Self Service Password Request HTTP application does not apply any feedback on password quality or strength.

Prerequisites:
  • Notes ID Vault has been established and contains the NotesID’s of all users
  • User must be authenticated, preferably using Active Directory authentication as described in the previous post level 1
  • Custom Password Reset application template,
    Please note the template provided by IBM as part of the Domino server is not officially supported and is provided as example only. See Technote 1330905

Configuration

Setup instructions have already been provided by IBM, so I'm not describing those steps again.
Once completed you should have a functioning PW reset application. However, I would like to highlight a few important details
  • The agent and the form needs to be signed with an ID which has IDVault Password Reset authority
  • The ACL of this database must have an Administration server defined, the Admin server specified there must be the one that hosts the IDVault.

For improved usability I do recommend a little tuning:
  • Create a URL which users can remember, e.g. by creating a web redirect rule
    http://yourserver.domain.com/passwordreset ==> /pwreset.nsf
  • Modify the form “fmPasswordReset” to display your corporate password rules, e.g.
    “The new password must have a minimum of 8 characters. It must contain a mixture of lowercase alphabetic, uppercase alphabetic, numbers and special characters. Three of these four conditions must be met.”
  • Modify the source code to confirm the password change request has been submitted and to verify if password rules have been followed.
    Without this modification users will not get any feedback if the new password has been applied or not.
    so update the source code of the Form “Password Change” , Sub “OnSubmit” as follows:
var i = 0;
var k = 0;
var h = 0;
var have = [0, 0, 0, 0];
var characters = ["abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789"];
var minLen = 8;
var minDif = 3;
var pw1 = document.forms[0].pw1.value;
var pw2 = document.forms[0].pw2.value;
for (i=0; i {
       h = 3;
       for (k=0; k        {
               if(characters[k].indexOf(pw1.substr(i,1)) >= 0)
               {
                       h = k;
               }
       }
       have[h] = 1;
}

if ( pw1.length < minLen )
{
       alert("You must enter a password with at least " + minLen + " characters");
       return false
}
else if( pw1 != pw2 )
{
       alert("Entered password don't match");
       return false
}
else if( have[0] + have[1] + have[2] + have[3] < minDif )
{
       alert("Password must be more complex,  use Numbers, Lower-, Upper-, Special-Characters");
       return false
}
else
{
       alert("Thank you, your request has been submitted. The new password can be used now.");
       return true
}
  • In order to support clustered environments the source code of the agent “User Password Reset” needs to be updated as follows:
Set Doc = Session.DocumentContext
Call
Session.ResetUserPassword( session.Currentdatabase.Acl .Administrationserver,"",Doc.GetItemValue("pw1")(0))


Conclusion

Self Service Password Reset application combined with LDAP authentication will eliminate the need to distribute Notes ID passwords to end users.
Administrators can register new NotesID's with completely random passwords that they do not need to remember nor need to distribute to end users.
Notes client setup instructions can be simplified so that end users have to define the password themselfes before they can start Notes for the first time.

References:

Deploying a customized Discover page in IBM Notes 9.0.x- 17 March 2016 - (3) Comments

Thomas Hampel
 17 March 2016

Vlad Tatarincevs already described how to customize the Discover page in the Notes Client.
In his guide he is assuming that all Notes clients are installed in exactly in the same path. While this might be the case for small deployments, its often not the case for enterprise deployments.

What is this Discovery page based on?

When starting the Notes client for the first time, it creates a text file in the Notes Data directory called "populatedTemplate.txt"
This file is used as a reference for computing the Notes Discovery page which is stored in a file called "populatedHTML.htm" in the same directory.

Both files are nothing else than a HTML page which you can customize according to your needs, but since the file populatedHTML.html is overwritten every once in a while, you should not modify this file directly.
Instead apply your modifications to the "populatedTemplate.txt"

Example Customization

In my example the following customizations have been done:
Image:Deploying a customized Discover page in IBM Notes 9.0.x
This file unfortunately contains hardcoded file and path references to the Notes program directory which are unique to the current computer.
In order to deploy a customized discover page in an enterprise environment you'll need to replace the path with the correct path on every single workstation. .

Once you've done your customizations you'll need to replace hardcoded path references with a placeholder which can be updated with computer specific path information when rolling out your new discover page to end user workstations. To do this we will be using a small VBS script that will read the Notes program directory from the Windows registry (sorry, no Mac / Linux support in this example) and updates the placeholder used above with the correct path reference before copying the file into the Notes data directory.

So this is what you have to do:

1.) put your customized "populatedTemplate.txt" into a new directory, and rename the file to "DiscoveryTemplate.txt" - this file name is used in the VBS script
2.) search "DiscoveryTemplate.txt" for the path of your Notes program directory and replace it with the placeholder. In my case I'm using "@NOTESPROGRAMDIR@" which is used in the script later on.
3.) put the following VBS script into the same directory
InstallDiscoverPage.zip

Running the script will overwrite any current "populatedTemplate.txt" in the Notes data directory with the DiscoveryTemplate that contains your customizations.
To display the updated Discover page you need to close and reopen it in the Notes client, or just restart your Notes client once.

You can manually open the Discover page from within the "Open" menu
Image:Deploying a customized Discover page in IBM Notes 9.0.x
where the second item from the bottom is your customized Discover page.
Image:Deploying a customized Discover page in IBM Notes 9.0.x

Remarks
  • Upgrading the Notes client to a future version will most likely overwrite the file "populatedTemplate.txt", so all your customizations will be lost.
  • Yes, it would be possible to deploy a custom discovery page from within the Notes client, but in my experience most enterprise environments have some sort of software distribution method for rolling out patches.

PS: Thanks to Bjoern Wolfgardt for providing a few hints and Marc for testing.

Print Email Attachments automatically with a RaspberryPI- 23 June 2015 - (5) Comments

Thomas Hampel
 23 June 2015

I am tired of printing email attachments. Yes, I still need to print some of them e.g. invoices for tax computation or travel reimbursement needs, or credit card balance sheets for archiving them offline.
Most of them are e-mails with PDF file attachments which I need to print on a regular basis. In order to print them I need to be at home, using a device with apropriate printer drivers installed and connected to my home network.

There must be a more simple method, so lets see how to allow mobile or remote printing.


What options do we have for remote printing?
  • Google Cloud Print - would be the easiest option but who wants to forward personal data to Google?
  • Using web-connected printers like those from HP or EPSON or Canon, but my current printer(s) do work fine and I see no reason to replace them.
    Furthermore any mail would be routed to the vendors environment which I dont trust.
  • VPN - probably the best approach, but still requires printer drivers and VPN software to be installed.
    Since none of the options above satisfied my needs, lets see if we can build a solution ourselfes...maybe using a Raspberry Pi
    Main idea is to poll an IMAP account on a regular basis and if new mail will meet certain criteria then print the PDF file attachment.

    Image:Print Email Attachments automatically with a RaspberryPI

    Step 1 - Preparations

    Obviously you need to
    buy a Raspberry PI, the Model B+ is enough. You also need some further equipment like a memory card, power adapter, keyboard, etc.
    Beside
    installing and configuring the operating system you need to:
  • Enable SSH
  • Apply latest patches by running update and Upgrade
    $ sudo apt-get update -y && apt-get upgrade -y
  • Install updates automatically by using apt-cron
    $ sudo apt-get install apt-cron
  • Configure your network adapter preferably assign a static IP
  • Change system locale and keyboard layout to fit your needs
  • Don't forget to Change the default password
  • When using a WiFi dongle disable WiFi Adapter Power Saving Mode
    Step 2 - Set up a new IMAP (or POP3) account

    Contact your provider for a description how to do that. Make sure your provider supports SSL/TLS connections and make sure to enable antivirus/antispam control for your IMAP account.
    Remark: SmartCloud Notes / Connections Cloud users need to enable IMAP access first (
    see details)

    Step 3 - Import SSL Root certificate(s)

    SSH into your Raspberry PI and start by creating a new directory for this project
    mkdir pimailprint
    cd pimailprint
     

    For
    verification of SSL certificates we would like to store SSL certificates of our mail provider locally, preferably in another subdirectory.
    mkdir sslcerts
    wget {url-of-provider certificate} -O ./sslcerts/provider-name.cer
    c_rehash ./sslcerts/

    You can verify the functionality
    using OpenSSL

    Step 4 - Install Prerequisites

    Install the required packages

    sudo apt-get install fetchmail procmail uudeview

    Create a configuration file for fetchmail, in our case the file will be located in the project directory instead of the users home folder.
    With this configuration I'm using procmail as mail delivery agent in order to further process the inbound mail.

    nano ./fetchmail.conf

    using this configuration:

    set no bouncemail
    poll IMAP.YOUR-DOMAIN.COM

    service 993

    protocol imap

    user "YOUR-USERNAME"

    password "YOUR-PASSWORD"

    ssl

    sslcertck

    sslproto TLS1

    no keep

    mda "/usr/bin/procmail -m './procmail.conf'"

    Change file permissions so only you can open and see the file.

    chmod 700 ./fetchmail.conf

    Create a configuration file for procmail...

    nano ./procmail.conf

    and use this configuration which will store mails that contain an attachment in the folder ./maildata

    MAIL_DIR=./maildata
    VERBOSE=off

    LOGFILE=./logs/printmail.log

    :0

    *^content-Type:

    $MAIL_DIR/


    Step 5 - Install and Configure CUPS

    CUPS (Common Unix Printing System) allows any computer to act as a print server.
    Just refer to
    this page for installation and configuration instructions
    Remark: Make sure to set this printer to be your default printer.
    Once completed you can manage the printer queue remotely using https://[ip-address-or-dns-name-of-your-raspberrypi]:631

    Image:Print Email Attachments automatically with a RaspberryPI

    Step 4 - Build your Script

    Create a new shell script...

    touch ./printmail.sh
    chmod +x ./printmail.sh

    nano ./printmail.sh

    using the following code
    #!/bin/bash
    # Parameters

    BASEDIR=$(dirname $0)

    CURDIR=$(pwd)

    MAILDIR=./maildata

    LOGFILE=./logs/printmail.log

    ATTACH_DIR=./attachments

    # change directory

    echo "Switching directory to : $BASEDIR"

    cd $BASEDIR

    # create log file if it does not exist

    touch $LOGFILE

    date +%r-%-d/%-m/%-y >> $LOGFILE

    # fetch mail

    echo "Checking for new mail..."

    fetchmail -f ./fetchmail.conf -L $LOGFILE

    # process new mails

    shopt -s nullglob

    for i in $MAILDIR/new/*

    do

      echo "Processing : $i" | tee -a $LOGFILE

      uudeview $i -i -p $ATTACH_DIR/

    # process file attachments with space (thanks to Dr.B.)
       cd $ATTACH_DIR
       for e in ./*
           do
               mv "$e" "${e// /_}"
       done
       for f in *.PDF
           do
           mv $f ${f%.*}.pdf
       done
       cd $BASEDIR
    # end of Dr.B. patch
      echo "Printing PDFs" | tee -a $LOGFILE

      for x in $ATTACH_DIR/*.pdf

      do

              echo "Printing : $x" | tee -a $LOGFILE

              lpr $x

              echo "Deleting file : $x" | tee -a $LOGFILE

              rm $x | tee -a $LOGFILE

      done

      echo "Clean up and remove any other attachments"

      for y in $ATTACH_DIR/*

      do

              rm $y

      done

      # delete mail

      echo "Deleting mail : $i" | tee -a $LOGFILE

      rm $i | tee -a $LOGFILE

    done

    shopt -u nullglob

    echo "Job finished." | tee -a $LOGFILE

    cd $CURDIR


    Step 5 - Test and Scheduling

    in order to test the whole script, just run it :)

    ./printmail.sh
    To run it on a schedule, just add the whole path to crontab.
    crontab -e -u pi

    in my case it is enough to run this script once per hour, feel free to customize it to your needs

    @hourly  /home/pi/pimailprint/printmail.sh

    Image:Print Email Attachments automatically with a RaspberryPI

    Results

    By forwarding a mail to a specific email address I can now print attachments automatically. Back home all the documents I wanted have already been printed or will be printed when switching on my printer and I can quickly process them further on, e.g. for claiming travel expenses back.
    In my case I am forwarding mails manually to a new account if I want to print them. Of course it is also possible to use mail rules for processing mails automatically.

    Enhancement requests / what needs to be done:
    • End to end encryption with S/MIME
  • Reply to sender when print job has completed
  • Define printer settings based on acronym in subject line
    Remark: Feel free to use this script at your own risk.
  • Import & Export Internet Certificates Programatically- 18 June 2015 - (0) Comments

    Thomas Hampel
     18 June 2015

    We all know that Admins are lazy. Being lazy can be helpful when having development skills, especially to reduce the amount of helpdesk calls by automating boring work.
    How to import X509 certificates into a Notes ID when the certificate itself is stored in the Windows certificate store?

    S/MIME Import / Export Automation

    If needed, users can then export or import Internet Certificates directly from the Notes Client, but who wants to do that manually?
    Even exporting the certificate from the Notes ID is too complicated for most users...
    Image:Import & Export Internet Certificates Programatically

    Looking for an automated way to export Internet Certificates, the pubnames.ntf provides there are some undocumented @Formulas that can be found for working with X509 certificates
    • @X509Certificates([Subject];UserCertificate;"");
      Returns the list of subjects of the internet certificates stored in the person document field named "UserCertificate"
    • @Command([PKCS12ExportCertsFromNAB];UserCertificate;Certificate;Number;"0")
      Where "Number" is the element in the list returned by @X509Certificates

    In my opinion those @Functions still show too many dialog boxes, so lets try to make it more simple.
    The C-API documentation provides the functions required namely PKCS12_ExportIDFileToFile and PKCS12_ImportFileToIDFile.

    Wrapping both into a small script is easy...

    Declare
    Function PKCS12_ExportIDFileToFile Lib "nnotes" Alias "PKCS12_ExportIDFileToFile" (_
               ByVal pIdFilename As String,_
               ByVal pIdFilepassword As String,_
               ByVal pPKCS12Filename As String,_
               ByVal pPKCS12Filepassword As String,_
               ByVal ExportFlags As Long,_
               ByVal ReservedFlags As Long,_                
               Preserved As Any) As Integer

    Declare
    Function PKCS12_ImportFileToIDFile Lib "nnotes" Alias "PKCS12_ImportFileToIDFile" (_
               ByVal pPKCS12Filename As String,_
               ByVal pPKCS12Filepassword As String,_
               ByVal pIdFilename As String,_
               ByVal pIdFilepassword As String,_
               ByVal ImportFlags As Long,_
               ByVal ReservedFlags As Long,_                
               Preserved As Any) As Integer

    Const
    PKCS12_EXCLUDE_PRIVATEKEYS=&h00000001


    Calling those API's would be able to import a certificate from a file, but often the certificate has already been deployed to (e.g.) the Windows certificate store.
    It would have been easy to use a Windows API call to export a certificate into a file and then import it again back into the Notes ID using the Notes API calls above.
    Unfortunately M$ discontinued support for CAPICOM after Windows XP... so we have to use old school methods like using command line tools like Certutil

    still with the resulting functions you can Import and Export X509 certificates from the Windows certificate store to the NotesID and back.

    ImportInternetCertificatesFromOSCredentialStore.lss

    ExportnternetCertificatesToOSCredentialStore.lss

    As usual mind YMMV and feel free to further optimize the code to fit your needs-
    Please use at your own risk and report back any suggestions or improvements!

    Special Thanks to Marcus Floeser for providing the screenshot.

    Users can create new mails despite being over quota- 29 May 2015 - (0) Comments

    Thomas Hampel
     29 May 2015

    You have deployed mail quotas in your environment and your Notes Clients are configured to use local replicas or managed replicas.
    Still you experience mail files are growing over quota limits without user complaints. How is this possible?

    It seems there is a bug in the IBM Domino mail template version 9.0.1 which allows to create and send new mails even when the mail file is over quota.

    Reproducing the problem

    When working on the server replica:
    • create a new mail and try to save it will correctly display this warning:
      Image:Users can create new mails despite being over quota
    When working on the local replica:
    • Create a new mail will display this error message, but clicking OK allows to continue saving & sending the new mail.
      Image:Users can create new mails despite being over quota
      Notes.ini variables have been verified to be set correctly on the client
      Check_Quota_On_Mail_Create=1
      REPL_OBEYS_QUOTAS=1

    The problem is known to IBM and is documented as LO83693 "Enforcing Quotas on new mail creation in local based mail files not reliably working in Notes 9.0.1"

    How to fix it

    As usual there are two options:
    a) Wait for IBM to provide a new version of the mail template - maybe this will be done in the next major release.
    or
    b) fix it yourself by modifying the template with your Domino Designer client as described below:

    Within the QueryOpen event of the form(s)  "Memo", "Reply" and "Reply with History" , "To Do", "_Calendar Entry", etc. search for the quota checking code and remove the "Executive" statement incl. its brackets.
    Image:Users can create new mails despite being over quota

    Interesting to note that special forms do not contain this code so they do not need to be patched
    Image:Users can create new mails despite being over quota
    Please note that design elements need to be signed properly in order to avoid ECL warnings on the client side.

    References
    • LO83693: Enforcing Quotas on new mail creation in local based mail files not reliably working in Notes 9.0.1

    Special thanks to Michal Wolczyk for this analysis and Marc for finding this bug.

    Opening another mail file is causing Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected- 7 January 2015 - (2) Comments

    Thomas Hampel
     7 January 2015

    Problem:
    Opening the mail file of another person is causing the message "Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected" to be displayed:
    Image:Opening another mail file is causing Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected
    While IBM Technote 1303181 only provides a basic idea of what is wrong, it does not give any idea what can be done to fix it.
    So I had to look into details and quickly found the problem.

    Steps to reproduce

    In order to reproduce the problem, this is what you have to do:
    • Make sure you have the Notes.ini variable CHECK_QUOTA_ON_MAIL_CREATE set to 1
    • Open another person's mail file, this will write the current date at the end of the Notes.ini variable DELEGATED_MAIL_FILEx
    • Close your Notes client
    • Change the date format of your operating system from DD.MM.YYYY to MM/DD/YYYY (or the other way around)
    • Open the same other persons mail file again.

    Analysis

    Trying to find the root cause with debugging enabled shows a different error "*CE39918+421: Type mismatch"
    Image:Opening another mail file is causing Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected
    but at least it indiicates the problem is located in the Database Open script.
    Image:Opening another mail file is causing Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected

    What is causing this problem?

    Obviously it is a String to Date conversion issue. Storing a Date in a String to convert it back to a date is never a good idea. If you really need to do it you should not rely on the CDat function to work. Write your own function which does ignore the
    Regional settings - in specific the date format - of this workstation have been changed.

    Resolving the problem

    Change the date format of your operating system back to what it should be.
    If the date format of your computer is correct and the problem still persists, then manually update your Notes.ini and remove all lines starting with DELEGATED_MAIL_FILE or by updating the date format at the end of this line yourself.

    Permanent solution

    A perfect solution would require to update the mail template to be updated. in specific the script Library "CheckQuotas" contains a class called "CheckQuota" with the Sub "SetCalMgrINI"
    This sub contains several references where a string is being converted to a date. This is where additional verification is required to ensure the string value is a date which can be converted using the current regional settings.
    Image:Opening another mail file is causing Type mismatch in method CoerStrToNum: STRING found, DOUBLE expected

    Mail Rules Analyzer has been published- 29 September 2014 - (1) Comments

    Thomas Hampel
     29 September 2014

    Today OpenNTF published one of my contributions Mail Rules Analyzer
    It is a small tool for Domino Administrators to scan mail files on one many servers to find out if any mail rule has been set up for external forwarding of mails.

    Main use case is to analyze an environment to notify users who have such mail rules configured before preventing users from forwarding mails to external recipients
    Results can be grouped/sorted/analyzed later on. At present the tool will only scan for rules that will forward a mail to external recipients but certainly there is room for further improvement...
    Here are a few screenshot of the user interface:

    Image:Mail Rules Analyzer has been published

    Image:Mail Rules Analyzer has been published
    Please post your comments and ideas in the feature requests section of the project
    This is just the first publication out of a number of tools which our team has developed over time, we expect to publish them one by one in the near future.

    Special thanks to Julian Robichaux for allowing the design reuse of the OpenLog template.

    References:

    NotesAPI - Import Pictures into RichText Fields using Backend Classes- 26 August 2014 - (3) Comments

    Thomas Hampel
     26 August 2014

    Importing pictures into a RichText field as embedded object is easy in the Notes Client. One can use the File\Import function to get this done - unfortunately this function is not available when running scheduled agents on a server.
    So how can it be done?

    Some time ago
    Andre Guirard published a LotusScript example as part of the OpenNTF project LotusScript Gold Collection to import a picture using the NotesDXLExporter class to export an existing NotesDocument to XML while then injecting the new image including all its metadata into this XML.

    Oh and of course I know we could be using
    Tivoli Directory Integrator or commercial solutions such as...
    But why installing another software or using 3rd party solutions if there are existing API calls that can be used. So yet another - less expensive - method to import pictures into RichText is the Notes API.
    Beside being faster, this method is will also work for older versions of the Notes Client, so feel free to use this script for mass-import of pictures into the Domino Directory
     

    ImportPicturesToRichText.lss


    (Thanks to Rod Whiteley for this old
    forum post)

    Converting Private to Public folders- 6 February 2014 - (0) Comments

    Thomas Hampel
     6 February 2014

    After a migration from Exchange to Domino a customer reported that some folders are not visible iNotes but are available for the Notes Client.
    In this particular case the folders not showing up have been created as private folders...and private folders are not supported in iNotes as documented in IBM Technote 1445118

    Changing the field flags of the folder design element from private to public turned out not to be working anymore. A script which I have been using to resolve this problem with earlier versions of Notes did not work and just created a folder which can not be deleted/moved/renamed.
    So I wrote this small script to fix the problem by creating a new temp folder -which will not be private by default- and moving documents from the private folder into the newly created folder. Once done, deleting the private folder and renaming the new folder.

    One small drawback is that the original folder design will get lost because we are creating a brand new folder from the default folder design.
    However, feel free to use this script at your own risk.

    Convert-Private-to-Public-folders.lss

    Backup Notes ID on local computer- 14 January 2013 - (0) Comments

    Thomas Hampel
     14 January 2013

    On special request of a customer, I'm posting a little LotusScript to back up the current NotesID locally.


            Dim s As New NotesSession
            Dim NotesID$, BackupID$, NotesData$
           
            NotesData = s.Getenvironmentstring("Directory", True)
            NotesID$ = s.Getenvironmentstring("KeyFileName", True)
           
            '# check if the 2nd character in the string NotesID is a ':'
            If Not Right(Left(NotesID$,2),1) = ":" Then
                    '# NotesID is located within Data Directory
                    NotesID$ = NotesData$ & "\" & NotesID$                
            End If
            Print "Current NotesID is : " & NotesID$
           
            BackupID$ = NotesID$ & ".bak"
            Print "Backup will be stored in : " & BackupID$
           
            If Dir$ (BackupID$,0)="" Then
                    '# No previous backup found, so okay to continue
            Else
                    '# Previous backup found, so deleting existing file and create a new backup
                    Print "Previous backup found, so deleting existing file and create a new backup"
                    Kill BackupID$
            End If
            Print "Creating a backup of your NotesID in : " & BackupID$
           
            FileCopy NotesID$, BackupID$
            MsgBox "A backup of you Notes User ID was created in " & Chr(13) & BackupID$

    Exporting Notes Documents- 2 October 2012 - (0) Comments

    Thomas Hampel
     2 October 2012

    A customer wanted to have all attachments of some selected Notes document exported to the file system and also wanted to keep an option for developers to access the metadata of the original Notes document.
    Nothing easier than that, so I wrote this small script to get the job done.


    First the entire document is exported into DXL, then all attachments are detached to the file system. Both parts are not rocket science, but some people might want to reuse the code.
    To avoid name conflicts while detaching files a folder is created for each Notes document so all attachments of this Notes document will be stored in this subfolder.


    Option
    Public
    Option
    Declare
    Dim
    gCounter&
    Sub
    Initialize
         
    Dim s As New NotesSession
         
    Dim coll As NotesDocumentCollection
         
    Dim BasePath$

          BasePath$ =
    InputBox ("Export data to path...: ", "Export", "C:\")
         
         
    '# add backslash at the end
         
    If right (BasePath$,1) <> "\" Then BasePath$ = BasePath$ & "\"
         
         
    Print "Using BasePath : " & BasePath$
         
         
    Set coll = s.currentdatabase.Unprocesseddocuments
         
    If coll Is Nothing Then
                 
    MessageBox "No documents selected"
         
    Else
                 
    Print "Processing " & coll.count & " documents..."
                 
    Call ExportToDXL (coll, BasePath$)
                 
    Call ExportToFile (coll, BasePath$)
                 
    MessageBox "Export completed."
         
    End If        
    End
    Sub

    Function
    ExportToDXL (Coll As NotesDocumentCollection, BasePath As String)
         
    Dim session As New NotesSession
         
    Dim stream As NotesStream
         
    Dim DXLfilename$
         
    Dim doc As NotesDocument
         
    Dim tdoc As NotesDocument
         
    Dim exporter As NotesDXLExporter
         
         
    If coll Is Nothing Then Exit function
         
    Set doc = coll.getfirstdocument
         
    While Not doc Is Nothing
                 
    Set tdoc = coll.getNextDocument (doc)
                 
    '# Open xml file named after current database
                 
    Set stream = session.CreateStream
                  DXLfilename$ = BasePath$ & doc.universalid &
    ".dxl"
                 
    If Not stream.Open(DXLfilename$) Then
                         
    MessageBox "Cannot open " & DXLfilename$,, "Error"
                         
    Exit Function
                 
    End If
                 
                 
    '# kick off the exporter process
                 
    Set exporter = session.CreateDXLExporter
                 
    Call exporter.SetInput(doc)
                 
    Call exporter.SetOutput(stream)
                 
    Call exporter.Process
                 
                 
    Set doc = tdoc
         
    Wend
    End
    Function

    Function
    ExportToFile (coll As NotesDocumentCollection, BasePath As String)
            On Error GoTo ErrH
            Dim doc As NotesDocument
            Dim tdoc As NotesDocument
            Dim rtitem As variant
            Dim targetpath$, fname$
            Dim FieldList(0) As String
            Dim oba As Variant
           
            '# define which fields to scan for attachments
            FieldList (0) = "Body"
           
            If coll Is Nothing Then Exit Function
           
            Set doc = coll.getfirstdocument
            While Not doc Is Nothing
                    Set tdoc = coll.getNextDocument (doc)
                    If doc.Hasembedded Then
                            targetpath$ = BasePath$ & doc.universalid & "\"
                           
                            If Dir$ (BasePath$ & doc.universalid, 16) = "" Then MkDir targetpath$
                           
                            '# loop list of fields
                            ForAll f In FieldList
                                     Set rtitem = doc.GetFirstItem(f)
                                     If Not rtitem Is Nothing Then
                                            If (rtitem.Type = RICHTEXT ) Then
                                                    '# make sure the field contains some objects and detach
                                                    If IsArray(rtitem.embeddedObjects) Then
                                                            ForAll o In rtitem.EmbeddedObjects
                                                                    If ( o.Type = EMBED_ATTACHMENT ) Then
                                                                            Fname$=o.Name
                                                                            If FileExists (fname$) Then fname$ = CStr(gCounter&) & Fname$
                                                                            Call o.ExtractFile(targetPath$ & Fname$)
                                                                            gCounter& = gCounter& + 1
                                                                    End If
                                                            End ForAll
                                                    End If

                                            End If
                                    End If
                            End ForAll
                    End If
                    Set doc = tdoc
            Wend
    continue:
            Exit Function
           
    errH:
            Stop
            Print "Error " & Err() & " in line " & Erl() & " - " & Error
            Resume continue
    End Function

    Profile documents and Author rights in ACL- 30 July 2012 - (0) Comments

    Thomas Hampel
     30 July 2012

    What if a developer is using user specific profile documents to store some settings in a Domino application.
    In this example users have Author access with the ability to create new documents and the ability to write public documents, no roles and no reader or author name fields are used in any document.

    Image:Profile documents and Author rights in ACL

    I'm wondering why users are not able to modify their own profile document by using the simple formula @Command([EditProfile]; "profile"; @Username)

    Of course developers will refer to the Designer Help or
    this technote where IBM clearly states:

    In order to edit profile documents, including your own profile, using @Command([EditProfile]), you must have at least Editor access or Author access in the ACL plus inclusion in an Author field.


    so it sounds like the user name must be listed in an author name field in order to modify an existing userprofile.


    Unfortunately in reality it seems to be working slightly different... see this example:

    I've created a new form to be used as a profile document, the form contained only a single field

    Image:Profile documents and Author rights in ACL
    Additionally I've created a small agent with the following code:


    Sub
    Initialize
           
    Dim s As New NotesSession
           
    Dim doc As NotesDocument
           
    Dim ws As New NotesUIWorkspace
           
           
    Set doc = s.currentdatabase.Getprofiledocument("profile", s.Effectiveusername)
           
           
    '# allows to modify the field values in the backend
           
    Call doc.Replaceitemvalue("Test", "test")
           
    Call doc.Save(true, false)
           
           
    '# allows to modify field values using the frontend
           
    Call ws.Dialogbox("profile", true, true, false, false, false, false, "Test", doc, false, false, false)
           
    Call doc.Save(True, False)
           
           
    '# does NOT allow to modify the document
           
    Call ws.Editprofile("profile", s.Effectiveusername)
    End
    Sub

    It seems like its possible to modify userprofile documents (which dont have an author name field) even when you dont have author access to the document itself.
    To clarify: the application was put on a server and access rights were limited to Author.

    Image:Profile documents and Author rights in ACL

    I'm wondering if there's any good explanation for this behavior.

    Update : The problem has been filed as SPR (Software Problem Report) # RGAU8WZE2X and the Customer Report, APAR # LO71028 was created.

    Signing and deploying Eclipse Plugins into Notes Clients- 26 June 2012 - (2) Comments

    Thomas Hampel
     26 June 2012

    Installing Eclipse plugins in a Notes client is a simple task. I'm sure users would be even more happy if admins would sign them properly before rolling them out.
    Otherwise, meaning when they are not signed, or if signed with an invalid signature, users will see messages like this:
    Image:Signing and deploying Eclipse Plugins into Notes Clients

    For a quick and dirty solution it would be possible set some preferences in the plugin_customization.ini or in the Notes client so that it will not show these warnings at all.
    Unfortunately this will lower the security of the entire environment and therefore is not recommended.

    The better method is to sign the plugin properly with a self signed certificate and then create a trust relationship with a Domino root certificate.
    So these are the actions that need to be performed:
    1.) Extract the Eclipse update site you want to sign to a temporary location on your hard disk
    2.) Detach this command file to the same folder location where the file "site.xml" is located
    signupdatesite.cmd
    3.) Edit the file and customize the settings according to your needs - see remarks within the file.
    4.) Run the .cmd file
    5.) Save a copy of the .keystore, .cer and sign_.cer files, they can be used to sign new release plugin if required.
    6.) Import the new certificate (.cer) into the Domino server
    7.) Create a cross-certificate from the internet certificate
    8.) Publish the certificate to clients through security policy settings
    9.) Create a new NSF based Eclipse update site and import the local update site from the temporary location (see step 1)
    10.) Create a widget catalog
    11.) Create a new widget using the Toolbar icon "Getting started with Widgets"  Image:Signing and deploying Eclipse Plugins into Notes Clients and choose "Features and Plugins"
    Image:Signing and deploying Eclipse Plugins into Notes Clients

    12.) Add the widget created to the widget catalog created in step 10 and don't forget to define a meaningful title and category. (e.g. Autoinstall) if you want the widget to be applied automatically. See next step for details.
    13.) In the Domino Directory update the Desktop policy settings to include the newly created Widget catalog
    Image:Signing and deploying Eclipse Plugins into Notes Clients

    All together it will allow automatically distributing plugins in the Notes client without error messages and without overall lowering security.
    Well, one prompt remains....
    Image:Signing and deploying Eclipse Plugins into Notes Clients

    How to enable/disable advanced DB properties such as DAOS- 1 September 2011 - (2) Comments

    Thomas Hampel
     1 September 2011

    Is it possible to set / remove the DAOS - flag in the advanced DB properties via Script??

    Up to now I thought its possible to do it in the same way as for all the other DB flags as shown in this technote.

    https://www-304.ibm.com/support/docview.wss?rs=899&uid=swg21244071

    But it looks like the DAOS flag isnt stored in there....

    Well in fact they are stored in there... but they are only exposed with ODS51 and the flag is not written to the $Flags field but written to a $DAOS field.


    $DAOS=1 means enabled

    $DAOS=0 means disabled

    One could set the flag by using the small script supplied in the technote above and referring to the $DAOS field instead, but wait there's a better option:


    Just use an (undocumented) LotusScript method "GetOption" and "SetOption" of the NotesDatabase class.

    Call NotesDatabase.SetOption(81,true) will enable DAOS

    Option
    Public
    Option
    Declare

    Sub
    Initialize
           
    '# Server name in canonical format, use "" for client:
           
    Const Servername$ = ">>>your server name here<<<"
           
    Dim db As NotesDatabase
           
    Dim dbdir As New NotesDbDirectory(servername)
           
    Set db = dbdir.GetFirstDatabase(DATABASE)
           
    While Not db Is Nothing
                   
    '# Skip databases which you don't have access to
                   
    On Error 4060 GoTo Error4060
                   
    Call db.Open(servername, db.FilePath)
                   
    Call db.setoption(DBOPT_LZCOMPRESSION, True)
                   
    Call db.setoption(81, True)        '# DAOS Enable
    GetNextDb:

                   
    Set db = dbdir.GetNextDatabase()
           
    Wend
           
    Exit Sub
    Error4060:

           
    '# If the code reaches here then the agent does not have access rights to the db.
           
    Print db.FilePath & " incorrect rights to access!"
           
    Resume GetNextDb
    End
    Sub

    Extract file name and display in a view- 24 September 2010 - (0) Comments

    Thomas Hampel
     24 September 2010

    If you want to display the file name in a view, but you only have a field containing file and pathname, here is a small formula to get the file name only.

    List:=@Explode(FilePath;"\\");
    nrElm:=@Elements(List);
    @Subset(List;-1)
    Go ElsewhereSubscribe to RSSAboutStay ConnectedAnd More
    Thomas Hampel, All rights reserved.