Tuesday, 25 August 2015

IBM VERSE: Synchronize Recent Contacts from Notes Client to VERSE

Customers appreciate the new User Experience of IBM Verse, but the moment they start using it, the first problem they face is that while typing name, recent contacts are not available, which are there in Notes Client. So, customers were forced to either search customer emails or copy from Notes Client.

To avoid the same, I created a script to copy the Recent Contacts to My Contacts and Sync it to Server.

Steps are as follows: :

1.Create a Notes button using following code to Migrate Recent Contacts in Notes Client to My Contacts.

Sub Click(Source As Button)
    Dim s As New NotesSession
    Dim vw As NotesView
    Dim doc As NotesDocument
    Dim db As NotesDatabase
    Dim doc2 As NotesDocument
    On Err Goto ErrHandler
    Dim total As Integer, cnt As Integer
    msg = "Please ensure that you don't run this code multiple times, else it will create duplicates in your Addressbook. " + Chr(10) & _
    "Are you sure to run this code ?"
    If Messagebox(msg, 36, "Are you sure ? ") = 7  Then
        Msgbox "The action has been cancelled", 64, "Cancelled"
        Exit Sub
    End If
    Set db = s.GetDatabase("", "names.nsf")
    Set vw = db.GetView("RecentCollaborators")
    total = vw.AllEntries.Count
    cnt = 0
    Set doc = vw.GetFirstDocument
    While Not doc Is Nothing
        cnt = cnt + 1
        Print "Processing " & cnt & " / " & total & " document"
        Set doc2 = vw.GetNextDocument(doc)
        RCtype = doc.GetItemValue("type")
        If Lcase(RCtype(0)) = "group" Then
            'Skip the doc
            'Move to My Contacts
            Call RCReplace(doc, db)
        End If
        Set doc = doc2
    Messagebox "Migration process has completed.", 64, "Complete"
    Exit Sub
    Goto NextDoc
End Sub

Sub RCReplace(RCDoc As notesdocument, db As NotesDatabase)   
    On Error Resume Next
    Call RCDoc.replaceitemvalue("Form", "Person")  'DNT
    If Lcase(rcDoc.getitemvalue("Type")(0)) <> Lcase("PeRsOn") Then
        Call RCDoc.replaceitemvalue("Type", "Person")   'DNT
        'this code is in place for Mail-In Database records, with only  hierarchical name in Fullname item
        RCFN = rcdoc.getitemvalue("Fullname")
        If Ubound(RCFN) = 0 Then
            Dim FNname As New notesname(RCFN(0))
            CanonFN = FNname.canonical
            If CanonFN <> "" Then
                Redim NewFN(1)               
            End If
            NewFN(0) = FNname.canonical
            NewFN(1) = FNname.common
            Call RCdoc.replaceitemvalue("Fullname", NewFN)
        End If
        ' /end Mail-In Db specific code
    End If   
    Call RCdoc.replaceitemvalue("$AutoCreatedList", "")
    Call RCdoc.replaceitemvalue("$DPABState", "")
    Call RCdoc.replaceitemvalue("$DPAB_State", "")   
    Call RCDoc.save(False,False)
    Set newContact = RCdoc.CopyToDatabase( db )
    Call RCDoc.remove(True)
End Sub

Note: Click "Yes" if any prompt comes up for Trusting Code.

2. Goto Notes Client --> File Menu --> Preferences.

3. Open Contacts section and ensure "Enable Synchronize Contacts" option is enabled.


4. Goto Replication and Sync Tab and ensure that "Synchronize Contacts Replication is Enabled.


5. Once Synced, All the Recent Contacts will be available in IBM Verse as well !

For more details, refer to IBM Wiki.

IBM VERSE Hybrid Deployment via Pass-thru only environment – without Internet Connection at each Machine

For a BFSI Customer, I recently implemented IBM Verse Hybrid deployment as a PoC. The major requirements were as follows:

  • No Internet connection to be provided at each individual machine.
  • Internet Proxy license not available for majority of users. If needed for Mailing, the cost of Proxy license to be added to TCO.
  • No direct connection from any Domino Server in MZ to Internet

IBM Verse Hybrid deployment System requirement clearly states that Internet connectivity is required from each machine for Notes Client configuration. Also, each Domino Server should be able to reach to Cloud Servers for Mail routing.

We addressed the challenge in two parts:

1. Configured On-premise Domino Servers to reach Cloud Servers via Pass-thru.

  • To achieve the same, create Connection document to Cloud Server OU via Pass-thru server.
  • In Pass-thru server, allow “*/CLOUD/<CUSTOMER_ORG>” as Allowed Destination via Pass-thru server. Also, allow all users to access the Pass-thru server by adding “*” to the “Who can access the Server” field.
  • Once done, trace the Cloud Servers from On-premise server. The connection should get established via Pass-thru server.

2.  Configure Notes Client to connect to Cloud servers via Pass-thru:

  • In this scenario, default method of downloading config.nsf and running won’t work, as config.nsf require internet connectivity over port 1352 NRPC to connect to Cloud servers.
  • To overcome this challenge, I created below script, which creates one Connection document to Pass-thru Server, one connection document to Cloud Servers using Pass-thru server.
  • Also, it modifies current location to ensure that Cloud Server is now configured as Home Mail Server in Notes Client. This information is available in On-premise directory (replicated via Directory Sync).
  • Additional Location doc can be created as well to allow users to connect directly to Cloud servers from Home using Internet connectivity from their Laptops.

Sub Click(Source As Button)
    Dim Workspace As New NotesUIWorkspace
    Dim UIDdoc As NotesUIDocument
    'Create Connection Doc to Pass-thru Server
    Set uidoc = workspace.composedocument("","names.nsf","Connection")
    Call uidoc.fieldsettext("ConnectionType","Local Area Network")
    Call uidoc.refreshhideformulas
    Call uidoc.fieldsettext("PortName","TCPIP")
    Call uidoc.fieldsettext("LanPortName","TCPIP")
    Call uidoc.fieldsettext("ConnectionLocation","*")
    Call uidoc.refreshhideformulas
    Call uidoc.fieldsettext("Destination","<PASS_THRU_SERVER>/<OU>/<CUSTOMER_ORG>")
    Call uidoc.fieldsettext("OptionalNetworkAddress","<IP_ADDRESS_OF_PASS_THRU>")
    Call uidoc.fieldsettext("Source","*")
    Call uidoc.refresh
    Call uidoc.save
    Call uidoc.close
    Set uidoc = workspace.composedocument("","names.nsf","Connection")
    Call uidoc.fieldsettext("ConnectionType","Passthru Server")
    Call uidoc.refreshhideformulas
    Call uidoc.fieldsettext("PassthruServer","<PASS_THRU_SERVER>/<OU>/<CUSTOMER_ORG>")
    Call uidoc.fieldsettext("ConnectionLocation","*")
    Call uidoc.refreshhideformulas
    Call uidoc.fieldsettext("Destination","*/CLOUD/<CUSTOMER_ORG>")
    Call uidoc.fieldsettext("Source","*")
    Call uidoc.refresh
    Call uidoc.save
    Call uidoc.close
    'Modify Current Location Document
    Dim session As New NotesSession
    Dim pnab As New NotesDatabase("", "names.nsf")
    Dim dbNab As NotesDatabase
    Dim currlocdoc As NotesDocument
    Dim vw As NotesView
    Dim doc As NotesDocument
    ' Pick out the second argument in Location INI variable (i.e. the Note IDof current location)
    'Following string extraction cannot be done with R5 StrLeft() StrRight() fcns b/c it won't work in R4 client, hence good old @formula Evaluate() to the rescue...
    CurrLocation$=session.GetEnvironmentString("Location", True)
    CurrLocationNoteID=Evaluate( { @Left(@Right("} & CurrLocation$ & {"; ",");",") } )
    Set currlocdoc=pnab.GetDocumentbyID( CurrLocationNoteID(0) )
    'Get the new Home Mail Server information from the Directory. Since directory is synchronized with Cloud, therefore On-premise directory will also contain the new Server information in updated person document of user.
    Set dbNab = session.GetDatabase("<IP_ADDRESS_ANY_ON_PREMISE_DIRECTORY_SERVER>", "names.nsf")
    Set vw = dbNab.GetView("People")
    Set doc = vw.GetDocumentByKey(session.UserName, True)
    If Not doc Is Nothing Then
        Call currlocdoc.replaceitemvalue ("MailServer", doc.MailServer(0))
        Call currlocdoc.save (True,True)
        Messagebox "Person Document not found. Please configure Location Document Manually.", 48, "Error Occured"
        Exit Sub
    End If
    Messagebox "Notes Client Configuration has completed successfully.", 64, "Configuration Complete"   
End Sub


Please feel free to reach me if any clarification required for the above description.

Notes Client: Insert Image Banner for All Outgoing Emails



Functionality: Insert Banner image for each new Mail in Notes Client.


1. Insert Banner into CalendarProfile.

Create Agent in Mailfile and name it like “Insert Banner”

Ensure that the banner image is available on Local machine. Update the path in below code before running the agent.

Run the code one time. It’ll create a RichText item in CalendarProfile and it’ll be used for inserting in new mails.

    Agent Insert Banner
    Created Aug 25, 2015 by Vikas Tiwari2/India/IBM
    Description: Comments for Agent
Option Public
Option Declare

Sub Initialize
    'Dim w As New NotesUIWorkspace
    Dim s As New NotesSession
    Dim db As NotesDatabase
    Dim doc As NotesDocument
    Set db = s.Currentdatabase
    Set doc = db.Getprofiledocument("CalendarProfile") 'CalendarProfile
    If EmbedPictureIntoRichText(doc, "D:/banner.jpg") Then
        MsgBox "success"
        MsgBox "error"
    End If
End Sub

Sub Terminate
End Sub

Function EmbedPictureIntoRichText(doc As NotesDocument, strFilePath As String) As Boolean
    EmbedPictureIntoRichText = False
    Dim session As New NotesSession
    Dim db As NotesDatabase
    Dim body As NotesMIMEEntity
    Dim header As NotesMIMEHeader
    Dim child As NotesMIMEEntity
    Dim stream As NotesStream
    Dim fileFormat As String
    Dim rtitemA As NotesRichTextItem
    Dim rtitemB As NotesRichTextItem
    Set db = doc.Parentdatabase
    On Err GoTo ErrHandler
    'Delete DummyRichText
    Set rtitemB = doc.GetFirstItem("BannerField")
    If Not rtitemB Is Nothing Then
        Call rtitemB.Remove()
    End If
    Set stream = session.CreateStream
    'Call stream.Open(strFilePath)
    Set body = doc.CreateMIMEEntity("BannerField")
    Set header = body.CreateHeader("Content-Type")
    Call header.SetHeaderVal("multipart/mixed")
    Set child = body.CreateChildEntity
    Call stream.WriteText(Chr(10) & Chr(10))
    Call child.SetContentFromText(stream, "text/plain", ENC_NONE)
    Call stream.Truncate
    Call stream.close()
    REM Create another child entity
    Set stream = session.CreateStream
    Call stream.Open(strFilePath)
    'Set body = doc.CreateMIMEEntity("BannerField")
    'Set header = body.CreateHeader("Content-Type")
    'Call header.SetHeaderVal("multipart/mixed")
    Set child = body.CreateChildEntity()
    fileFormat = "image/jpeg" 'Other formats are "image/gif" "image/bmp"
    Call child.Setcontentfrombytes(stream, fileFormat, 1730)
    'Call child.EncodeContent(ENC_BASE64)
    'Call stream.Truncate
    Call stream.Close()
    Call doc.save(False, False) 'JUST TO REFRESH
    EmbedPictureIntoRichText = True
    Exit Function
    'not required
    Set rtitemA = doc.GetFirstItem("Body")
    Set rtitemB = doc.GetFirstItem("BannerField")
    Call rtitemA.AppendRTItem( rtitemB )
    Call rtitemB.Remove()
    Call doc.save(False, False)
    EmbedPictureIntoRichText = True
    Exit Function
    MsgBox "Error occurred: " & CStr(Err) & " : " & Error & " at line no. " & CStr(Erl)
End Function

2. Modify InsertSignature Function by inserting following code as per screenshot below:

If profileDoc.HasItem("BannerField") Then
        Call uiDoc.ImportItem(profileDoc, "BannerField")   
End If   


This code is just a starting point to help someone trying to achieve the desired functionality. If more automation is required, let me know I can guide for next steps.

Wednesday, 12 August 2015

Migrate your mail data using imapSync

Recently tried IMAPSync tool to migrate some mails off a google account to a local domino server as well as to my Connections cloud account. I used the below steps for the migration. Note that I used a windows machine to run the batch file and the syntax mentioned below apply to a windows desktop environment and would differ for a linux client.

1) Download and unzip the latest imapSync utility.
2) Edit the batch file with the below:

.\imapsync.exe ^
           --host1 imap.gmail.com ^
           --user1 "username@gmail.com" ^
           --password1 "gmailsecretpassword" ^
           --ssl1 ^
           --authmech1 LOGIN ^
           --host2 imap.notes.na.collabserv.com ^
           --user2 "collabservuser@collabservdomain.com" ^
           --password2 "collabservsecret" ^
           --ssl2 ^
           --maxbytespersecond 500000 ^
           --useheader="X-Gmail-Received" ^
           --useheader "Message-Id" ^
           --automap ^
--addheader ^
           --sep2 "/"  ^
           --prefix2 ""

3) Save the batch file
4) Run the batch file by double clicking the file

*** Edit Notes ***
Added the --addheader to synchronize the sent folder to Gmail/Sent folder
Added the --sep2 and --prefix2 to synchronize the nested folders.
Removed --skipcrossduplicates to make sure that messages marked with multiple labels appear in separate folders
*** End Edit Notes ***

To test the connections you could first use the --dry and --justfolders options..
Some points to take care..
A) Your google account should allow less secure devices to connect --> Link
B) Your google account should not be set for application passwords --> Link
C) You should have IMAP enabled on IBM Connections account

To test out the settings you can try telnet to the hosts on port 993.
To further test out the settings you could try to connect the two account using a mail client such as outlook / thunderbird over imap.

If you wish to migrate emails to a local domino server which doesn't use SSL, you would need to telnet on port 143 and the option --ssl2 will need to be removed in the above batch file.

The batch file for migrating mails to a local domino server over imap would look as below:

.\imapsync.exe ^
           --host1 imap.gmail.com ^
           --user1 "gmailuser@gmail.com" ^
           --password1 "gmailpassword" ^
    --ssl1 ^
        --authmech1 LOGIN ^
           --host2 domino.server.fqdn ^
           --user2 "dominouserid" ^
           --password2 "dominopassword" ^
                      --maxbytespersecond 500000 ^
           --useheader="X-Gmail-Received" ^
           --useheader "Message-Id" ^
           --automap ^

Thanks for great documentation provided by author of imapsync Gilles LAMIRAL -> http://imapsync.lamiral.info/

Wednesday, 5 August 2015

Connect to Multiple Networks simultaneously using Windows 7


I struggled to setup multiple networks working simultaneously.. Sharing my findings and steps involved:

1. Set Manual Metric Setting for all Network interfaces. Lower value takes the preference! So, set lowest value for the network which should be opened for most requests like Internet connection.


Detailed steps:

1. Open Command Prompt and type: route print - you will see a list of active routes, the last column displaying their "metric". Lower metric routes are preferred over higher ones.
2. Open the Network Adapter Properties (Control Panel > Network and Internet > Network Connections > right-click on adapter and choose Properties)
3. Open the properties of Internet Protocol Version 4 (TCP/IPv4).
4. Click on Advanced.
5. Untick "Automatic Metric" and set the interface metric to a number.
6. Hit OK until you close the Network Adapter properties.
7. Repeat steps 2-6 for your other network adapter(s) choosing different metrics. Remember lower metrics are preferred over higher ones.

2. Only Single Gateway Interface configuration required. i.e. For most preferred Interface, define the Gateway, for rest of the Network Adaptors, use Static IP Configuration without Gateway setting.


3. For Accessing Internal Servers, either access them first and then change the Metric setting else specify the Static Route using following commands:

route –p add destination mask subnetmask gateway metric costmetric if interface

For eg.

route -p add mask metric 2

4. Now, you can access both networks from single machine !