Accessing "Arbitrary Data" in Notes Documents (Sametime BuddyList) followup
Yesterday I stated " Neither the LotusScript nor Java API allows us to process this item type" about a Notes item type "Arbitrary Data". Today I stand corrected. It turns out, than since R65 we have NoesDocument.GetItemValueCustomDataBytes and NotesItem.GetValueCustomDataBytes. Carl Tyler from Epilio (Remember: Sametime without Epilio is like Sushi without Wasabi) filled in the missing blanks. The method requires a data type and Carl shared that the data type for the BuddyList is
So I wrote a little agent that now extracts the whole buddylists into the
As usual: YMMV
UbqOpaque
. The second important information: Buddy lists are stored in an item named "8193". If a buddy lists grows to big additional items are added "8193.1" "8193.2" etc.
So I wrote a little agent that now extracts the whole buddylists into the
C:\export\
directory. One interesting observation. All budy lists (and I had some with double byte names) started with the bytes 110 7 0 0 before the <?xml... First I though that to be Unicode Byte Order Marker (BOM), but it seems they are not related to that. So when you want to process these files you might need to edit them first. Inside my Java class I take care of that. The updated code can be downloaded including the source code as before. When running the report I found that I had to open and save the exportbuddies.xml before the XSLT transformation would run properly.
As usual: YMMV
-
%REM
-
Agent ExportBuddyLists
-
Created Jul 1, 2010 by Stephan H Wissel/Singapore/IBM
-
Description: Exports Buddylists
-
%END REM
-
Option Public
-
Option Declare
-
-
-
Dim s As NotesSession
-
Dim exportDir As String 'Defaults to C:\Export\, set in Initialize
-
Dim defaultItemName As String
-
Sub Initialize
-
Dim db As NotesDatabase
-
Dim v As NotesView
-
Dim doc As NotesDocument
-
Dim users As NotesStream
-
Dim outUserName As String
-
Dim outCounter As Integer
-
-
On Error GoTo Err_Initialize
-
-
Set s = New NotesSession
-
Set db = s. Currentdatabase
-
Set v = db. Getview ( "Storage" )
-
Set users = s. Createstream ( )
-
-
'TODO: you need to change these values
-
exportDir = "C:\export\"
-
defaultItemName = "8193" 'The item with the BuddyList
-
outUserName = exportDir + "exportbuddies.xml"
-
-
If Dir$ (outUserName ) <> "" Then
-
Kill outUserName
-
End If
-
Call users. Open (outUserName, "UTF-8" )
-
-
Set doc = v. Getfirstdocument ( )
-
Call users. Writetext ( "<users>", EOL_CRLF )
-
outCounter = 0
-
-
Do Until doc Is Nothing
-
outCounter = outCounter + ExportOneBuddyList (doc, outCounter, users )
-
Set doc = v. Getnextdocument (doc )
-
Loop
-
-
Call users. Writetext ( "</users>", EOL_CRLF )
-
Call users. Close ( )
-
Print CStr (outCounter ) + " Users exported"
-
-
Exit_Initialize:
-
Exit Sub
-
-
Err_Initialize:
-
MsgBox Error$,, "Line "+ CStr ( Erl )
-
Resume Exit_Initialize
-
End Sub
-
Sub Terminate
-
-
End Sub
-
-
-
%REM
-
Function ExportOneBuddyList
-
Description: Exports a buddylist if it has the 8193 item
-
%END REM
-
Function ExportOneBuddyList (doc As NotesDocument, outCounter As Integer, users As NotesStream ) As Integer
-
Dim curUser As String
-
Dim userLine As String
-
Dim curName As NotesName
-
Dim out As NotesStream
-
Dim outFileName As String
-
-
On Error GoTo Err_ExportOneBuddyList
-
-
ExportOneBuddyList = 0
-
-
If Not doc. HasItem (defaultItemName ) Then
-
If doc. Hasitem ( "0" ) Then
-
Print "Document has old buddy list, very bad " & doc. Universalid
-
End If
-
Exit Function 'We don't export if there is nothing
-
End If
-
-
'Get the user name
-
curUser = doc. Getitemvalue ( "storageUserId" ) ( 0 )
-
Set curName = s. Createname (curUser )
-
-
outFileName = exportDir + |BuddyList|+ CStr (outCounter )+ |.xml|
-
-
If Dir$ (outFileName ) <> "" Then
-
Kill outFileName
-
End If
-
-
Set out = s. createStream
-
Call out. open (outFileName, "Unicode" )
-
-
Call PopulateStreamWithBuddyList (doc, out )
-
-
userLine = |<user id="|+ CStr (outCounter )+ |">|+curName. Abbreviated+ |</user>|
-
-
Call users. Writetext (userLine, EOL_CRLF )
-
-
'Once we got here it worked
-
ExportOneBuddyList = 1
-
-
Exit_ExportOneBuddyList:
-
On Error Resume Next
-
If Not out Is Nothing Then
-
Call out. Close ( )
-
End If
-
Exit Function
-
-
Err_ExportOneBuddyList:
-
Print Error$ & " in line " & CStr ( Erl ) & ", function ExportOneBuddyList for user: " & curUser
-
ExportOneBuddyList = 0
-
Resume Exit_ExportOneBuddyList
-
-
End Function
-
-
-
%REM
-
Sub WriteItemBytesToStream
-
Description: Writes out all the data found in an item into the
-
Output stream for closure
-
%END REM
-
Sub WriteItemBytesToStream (doc As NotesDocument, itemName As String, out As NotesStream )
-
Dim bytes As Variant
-
Dim isXMLStart As Boolean
-
Dim DataTypeStorage As String
-
Dim tempStream As NotesStream
-
Dim startByte As Long
-
-
On Error GoTo Err_WriteItemBytesToStream
-
-
'The custom data type Lotus use to store Sametime Data
-
DataTypeStorage = "UbqOpaque"
-
bytes = doc. GetItemValueCustomDataBytes (itemName, DataTypeStorage )
-
-
'we write out everything
-
Call out. Write (bytes )
-
-
Exit_WriteItemBytesToStream:
-
Exit Sub
-
-
Err_WriteItemBytesToStream:
-
Print Error$ & " in WriteItemBytesToStream"
-
Resume Exit_WriteItemBytesToStream
-
-
End Sub
-
%REM
-
Sub PopulateStreamWithBuddyList
-
Description: Writes the item from 8193 into the stream (and subsequential subitems)
-
%END REM
-
Sub PopulateStreamWithBuddyList (doc As NotesDocument, out As NotesStream )
-
Dim itemCounter As Integer
-
Dim curItemName As String
-
-
-
-
'Initial check - should not be needed since we won't call a doc that doesn't have it
-
If Not doc. Hasitem (defaultItemName ) Then
-
Print "No item " & defaultItemName & "found"
-
Exit sub
-
End If
-
-
'One call is needed then the others are optional
-
Call WriteItemBytesToStream (doc, defaultItemName,out )
-
-
'If the Buddylist is REALLY large > 40k there are more items left
-
itemCounter = 1
-
curItemName = defaultItemName & "." & CStr (itemCounter )
-
-
Do While doc. Hasitem (curItemName )
-
'Write the additional items out
-
Call WriteItemBytesToStream (doc, curItemName,out )
-
'Next set
-
itemCounter = itemCounter + 1
-
curItemName = defaultItemName & "." & CStr (itemCounter )
-
Loop
-
-
-
End Sub
Posted by Stephan H Wissel on 01 July 2010 | Comments (2) | categories: Show-N-Tell Thursday