wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

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 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
  1. %REM
  2.     Agent ExportBuddyLists
  3.     Created Jul 1, 2010 by Stephan H Wissel/Singapore/IBM
  4.     Description: Exports Buddylists
  5. %END REM
  6. Option Public
  7. Option Declare
  8.  
  9.  
  10. Dim s As NotesSession
  11. Dim exportDir As String 'Defaults to C:\Export\, set in Initialize
  12. Dim defaultItemName As String
  13. Sub Initialize
  14.     Dim db As NotesDatabase
  15.     Dim v As NotesView
  16.     Dim doc As NotesDocument
  17.     Dim users As NotesStream
  18.     Dim outUserName As String
  19.     Dim outCounter As Integer
  20.    
  21.     On Error GoTo Err_Initialize
  22.    
  23.     Set s = New NotesSession
  24.     Set db = s. Currentdatabase
  25.     Set v = db. Getview ( "Storage" )
  26.     Set users = s. Createstream ( )
  27.    
  28.     'TODO: you need to change these values
  29.     exportDir = "C:\export\"
  30.     defaultItemName = "8193" 'The item with the BuddyList
  31.     outUserName = exportDir + "exportbuddies.xml"
  32.    
  33.     If Dir$ (outUserName ) <> "" Then
  34.         Kill outUserName
  35.     End If
  36.     Call users. Open (outUserName, "UTF-8" )
  37.    
  38.     Set doc = v. Getfirstdocument ( )
  39.     Call users. Writetext ( "<users>", EOL_CRLF )
  40.     outCounter = 0
  41.    
  42.     Do Until doc Is Nothing
  43.         outCounter = outCounter + ExportOneBuddyList (doc, outCounter, users )
  44.         Set doc = v. Getnextdocument (doc )
  45.     Loop
  46.    
  47.     Call users. Writetext ( "</users>", EOL_CRLF )
  48.     Call users. Close ( )
  49.     Print CStr (outCounter ) + " Users exported"
  50.    
  51. Exit_Initialize:
  52.     Exit Sub
  53.    
  54. Err_Initialize:
  55.     MsgBox Error$,, "Line "+ CStr ( Erl )
  56.     Resume Exit_Initialize
  57. End Sub
  58. Sub Terminate
  59.    
  60. End Sub
  61.  
  62.  
  63. %REM
  64.     Function ExportOneBuddyList
  65.     Description: Exports a buddylist if it has the 8193 item
  66. %END REM
  67. Function ExportOneBuddyList (doc As NotesDocument, outCounter As Integer, users As NotesStream ) As Integer
  68.     Dim curUser As String
  69.     Dim userLine As String
  70.     Dim curName As NotesName
  71.     Dim out As NotesStream
  72.     Dim outFileName As String
  73.    
  74.     On Error GoTo Err_ExportOneBuddyList
  75.    
  76.     ExportOneBuddyList = 0
  77.    
  78.     If Not doc. HasItem (defaultItemName ) Then
  79.         If doc. Hasitem ( "0" ) Then
  80.             Print "Document has old buddy list, very bad " & doc. Universalid
  81.         End If
  82.         Exit Function 'We don't export if there is nothing
  83.     End If
  84.    
  85.     'Get the user name
  86.     curUser = doc. Getitemvalue ( "storageUserId" ) ( 0 )
  87.     Set curName = s. Createname (curUser )
  88.    
  89.     outFileName = exportDir + |BuddyList|+ CStr (outCounter )+ |.xml|
  90.    
  91.     If Dir$ (outFileName ) <> "" Then
  92.         Kill outFileName
  93.     End If
  94.    
  95.     Set out = s. createStream
  96.     Call out. open (outFileName, "Unicode" )
  97.    
  98.     Call PopulateStreamWithBuddyList (doc, out )
  99.        
  100.     userLine = |<user id="|+ CStr (outCounter )+ |">|+curName. Abbreviated+ |</user>|
  101.    
  102.     Call users. Writetext (userLine, EOL_CRLF )
  103.    
  104.     'Once we got here it worked
  105.     ExportOneBuddyList = 1
  106.    
  107. Exit_ExportOneBuddyList:
  108.     On Error Resume Next
  109.     If Not out Is Nothing Then
  110.         Call out. Close ( )
  111.     End If
  112.     Exit Function
  113.    
  114. Err_ExportOneBuddyList:
  115.     Print Error$ & " in line " & CStr ( Erl ) & ", function ExportOneBuddyList for user: " & curUser
  116.     ExportOneBuddyList = 0
  117.     Resume Exit_ExportOneBuddyList
  118.    
  119. End Function
  120.  
  121.  
  122. %REM
  123.     Sub WriteItemBytesToStream
  124.     Description: Writes out all the data found in an item into the
  125.     Output stream for closure
  126. %END REM
  127. Sub WriteItemBytesToStream (doc As NotesDocument, itemName As String, out As NotesStream )
  128.     Dim bytes As Variant
  129.     Dim isXMLStart As Boolean
  130.     Dim DataTypeStorage As String
  131.     Dim tempStream As NotesStream
  132.     Dim startByte As Long
  133.    
  134.     On Error GoTo Err_WriteItemBytesToStream
  135.    
  136.     'The custom data type Lotus use to store Sametime Data
  137.     DataTypeStorage = "UbqOpaque"
  138.     bytes = doc. GetItemValueCustomDataBytes (itemName, DataTypeStorage )
  139.    
  140.     'we write out everything
  141.     Call out. Write (bytes )  
  142.    
  143. Exit_WriteItemBytesToStream:
  144.     Exit Sub
  145.    
  146. Err_WriteItemBytesToStream:
  147.     Print Error$ & " in WriteItemBytesToStream"
  148.     Resume Exit_WriteItemBytesToStream
  149.    
  150. End Sub
  151. %REM
  152.     Sub PopulateStreamWithBuddyList
  153.     Description: Writes the item from 8193 into the stream (and subsequential subitems)
  154. %END REM
  155. Sub PopulateStreamWithBuddyList (doc As NotesDocument, out As NotesStream )
  156.     Dim itemCounter As Integer
  157.     Dim curItemName As String
  158.  
  159.  
  160.    
  161.     'Initial check - should not be needed since we won't call a doc that doesn't have it
  162.     If Not doc. Hasitem (defaultItemName ) Then
  163.         Print "No item " & defaultItemName & "found"
  164.         Exit sub
  165.     End If
  166.    
  167.     'One call is needed then the others are optional
  168.     Call WriteItemBytesToStream (doc, defaultItemName,out )
  169.    
  170.     'If the Buddylist is REALLY large > 40k there are more items left
  171.     itemCounter = 1
  172.     curItemName = defaultItemName & "." & CStr (itemCounter )
  173.    
  174.     Do While doc. Hasitem (curItemName )
  175.         'Write the additional items out
  176.         Call WriteItemBytesToStream (doc, curItemName,out )
  177.         'Next set
  178.         itemCounter = itemCounter + 1
  179.         curItemName = defaultItemName & "." & CStr (itemCounter )
  180.     Loop
  181.    
  182.    
  183. End Sub

Posted by on 01 July 2010 | Comments (2) | categories: Show-N-Tell Thursday

Comments

  1. posted by Doug on Wednesday 21 August 2013 AD:
    Stephan, We are working on moving our Sametime instance out of our primary domain to a new domain. The export process you explained here is great. But is there any similar process to import the modified xml files back into our new domain without user intervention?

    Thanks
  2. posted by Stephan H. Wissel on Wednesday 21 August 2013 AD:
    I wouldn't go the export/import route. Why not take the NSF and just copy the documents (if missing) or the few items 8192 over? Copying items avoids to do any conversion.