Wasn't sure where to post this, so I ended up here. Needed a way to see whether users at work were stashing stuff inside their mailboxes, so went on a search to find a report that would tell me. Started trying to use the COM interface, but fell short of the mark as far as being able to tell what size the email attachment actually used up on the server (Notes/Domino kindly compresses attachments, and will readily tell you how big the ORIGINAL filesize is, but if you want to know more, well...). After much hunting for information, found snippets of C/C++ and LotusScript code that would return the compressed filesize.
Of course, everyone I've told, and I'm sure most anyone reading this, will ask "Why the hell didn't you just use LotusScript or the C/C++ API supplied by Lotus/IBM?". I'm gonna give the same, tired cliched(?) answer - because it is there! Well, because I wanted to see if it could be done..in PB, of course! And I wouldn't be posting here if it couldn't!!
Have only tested on WinXP Pro w/SP2 and Notes 6.5.3 client and Version 6.5 of the C-API, but I'm sure the functions I use are applicable to at least Release 5.x and above. Please don't laugh at my code, this is my first PB program. Program will prompt firstly for a textfile with NSF names in, followed by an output filename. Then it will open a console window and spit its report out to it, as well as the output file specified.
Please be brutal with your criticisms!
(Question about using STATIC as opposed to PROTECTED: Does STATIC allocate storage in the heap and PROTECTED on the stack, hence I wouldn't see any difference in compiled filesizes?)
Oops! Forgot to specify, you'll need the Lotus C-API LIB file to compile, and the Lotus Notes client installed to run. So, I'm guessing 99.9% of you won't be abel to do much with this
Code: Select all
; TO DO:
;======
;
; Enable browsing of servers and multiple selection of NSFs instead of reading them from a file
;
; Reporting on person other than owner of NSF, in the From column (better reporting of TO/FROM info)
;
; Tidier, more structured (more OOP-like?) code, break down into more procedures
;
; Be able to choose which USER to login with, and/or specify which NOTES.INI to use
EnableExplicit
;-Constants
;{
#MAX_PATH_LEN = 1024
#NSF_INFO_SIZE = 128
#INFOPARSE_TITLE = 0
#INFOPARSE_CATEGORIES = 1
#INFOPARSE_CLASS = 2
#INFOPARSE_DESIGN_CLASS = 3
#NOTE_CLASS_DOCUMENT = $0001
#MAXPATH = 256
#NOTEID_LENGTH = 6
#DIRFILE = 0
#LOGFILE = 1
#MAX_STRING_LEN = 255
#MIN_STRING_LEN = 1
#MAXALPHATIMEDATE = 80+1
#ERR_ITEM_NOT_FOUND = $200+34
; /* Data Type Definitions from NSFDATA.H follow */
;
; /* Class definitions. Classes are defined To be the
; "generic" classes of Data type that the internal formula computation
; mechanism recognizes when doing recalcs. */
#CLASS_NOCOMPUTE = (0 << 8)
#CLASS_ERROR = (1 << 8)
#CLASS_UNAVAILABLE = (2 << 8)
#CLASS_NUMBER = (3 << 8)
#CLASS_TIME = (4 << 8)
#CLASS_TEXT = (5 << 8)
#CLASS_FORMULA = (6 << 8)
#CLASS_USERID = (7 << 8)
#CLASS_MASK = $ff00
; /* All datatypes below are passed To NSF in either host (machine-specific
; byte ordering And padding) Or canonical form (Intel 86 packed form).
; The format of each datatype, As it is passed To And from NSF functions,
; is listed below in the comment field Next To each of the Data types.
; (This host/canonical issue is Not applicable To Intel86 machines,
; because on that machine, they are the same And no conversion is required).
; On all other machines, use the ODS subroutine package To perform
; conversions of those datatypes in canonical format before they can
; be interpreted. */
;
; /* "Computable" Data Types */
#TYPE_ERROR = 0 + #CLASS_ERROR ;/* Host form */
#TYPE_UNAVAILABLE = 0 + #CLASS_UNAVAILABLE ;/* Host form */
#TYPE_TEXT = 0 + #CLASS_TEXT ;/* Host form */
#TYPE_TEXT_LIST = 1 + #CLASS_TEXT ;/* Host form */
#TYPE_NUMBER = 0 + #CLASS_NUMBER ;/* Host form */
#TYPE_NUMBER_RANGE = 1 + #CLASS_NUMBER ;/* Host form */
#TYPE_TIME = 0 + #CLASS_TIME ;/* Host form */
#TYPE_TIME_RANGE = 1 + #CLASS_TIME ;/* Host form */
#TYPE_FORMULA = 0 + #CLASS_FORMULA ;/* Canonical form */
#TYPE_USERID = 0 + #CLASS_USERID ;/* Host form */
; /* "Non-Computable" Data Types */
#TYPE_INVALID_OR_UNKNOWN = 0 + #CLASS_NOCOMPUTE ;/* Host form */
#TYPE_COMPOSITE = 1 + #CLASS_NOCOMPUTE ;/* Canonical form, >64K handled by more than one item of same name concatenated */
#TYPE_COLLATION = 2 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_OBJECT = 3 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_NOTEREF_LIST = 4 + #CLASS_NOCOMPUTE ;/* Host form */
#TYPE_VIEW_FORMAT = 5 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_ICON = 6 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_NOTELINK_LIST = 7 + #CLASS_NOCOMPUTE ;/* Host form */
#TYPE_SIGNATURE = 8 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_SEAL = 9 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_SEALDATA = 10 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_SEAL_LIST = 11 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_HIGHLIGHTS = 12 + #CLASS_NOCOMPUTE ;/* Host form */
#TYPE_WORKSHEET_DATA = 13 + #CLASS_NOCOMPUTE ;/* Used ONLY by Chronicle product */
; /* Canonical form */
#TYPE_USERDATA = 14 + #CLASS_NOCOMPUTE ;/* Arbitrary format Data - see format below */
; /* Canonical form */
#TYPE_QUERY = 15 + #CLASS_NOCOMPUTE ;/* Saved query CD records; Canonical form */
#TYPE_ACTION = 16 + #CLASS_NOCOMPUTE ;/* Saved action CD records; Canonical form */
#TYPE_ASSISTANT_INFO = 17 + #CLASS_NOCOMPUTE ;/* Saved assistant info */
#TYPE_VIEWMAP_DATASET = 18 + #CLASS_NOCOMPUTE ;/* Saved ViewMap dataset; Canonical form */
#TYPE_VIEWMAP_LAYOUT = 19 + #CLASS_NOCOMPUTE ;/* Saved ViewMap layout; Canonical form */
#TYPE_LSOBJECT = 20 + #CLASS_NOCOMPUTE ;/* Saved LS Object code For an agent. */
#TYPE_HTML = 21 + #CLASS_NOCOMPUTE ;/* LMBCS-encoded HTML, >64K handled by more than one item of same name concatenated */
#TYPE_SCHED_LIST = 22 + #CLASS_NOCOMPUTE ;/* Busy time schedule entries list; Host form */
#TYPE_CALENDAR_FORMAT = 24 + #CLASS_NOCOMPUTE ;/* Canonical form */
#TYPE_MIME_PART = 25 + #CLASS_NOCOMPUTE ;/* MIME body part; Canonical form */
#TYPE_RFC822_TEXT = 2 + #CLASS_TEXT ;/* RFC822( RFC2047) message header; Canonical form */
;}
;-Enumerations
;{
Enumeration
#NOCOMP
#HUFF
#LZ1
EndEnumeration
;}
;-Structures
;{
Structure BlockID
hPool.l
Block.l
EndStructure
Structure TIMEDATE
Innards.LONG[2]
EndStructure
Structure DBID
x.TIMEDATE
EndStructure
Structure NOTEID
x.LONG
EndStructure
Structure GLOBALINSTANCEID
File.DBID
Note.TIMEDATE
NoteID.NOTEID
EndStructure
Structure ORIGINATORID
File.DBID
Note.TIMEDATE
Sequence.LONG
SequenceTime.TIMEDATE
EndStructure
Structure SEARCH_MATCH
ID.GLOBALINSTANCEID
OriginatorID.ORIGINATORID
NoteClass.WORD
SERetFlags.BYTE
Privileges.BYTE
SummaryLength.WORD
EndStructure
Structure TFMT
Date.b ; /* Date Display Format */
Time.b ; /* Time Display Format */
Zone.b ; /* Time Zone Display Format */
Struc.b ; /* Overall Date/Time Structure */
EndStructure
Structure RANGE
ListEntries.w ;/* list entries following */
RangeEntries.w ;/* range entries following */
EndStructure
;}
;-Globals
;{
;*************************************************************
;*************************************************************
;**** ****
;**** Change following lines depending on Local or Server ****
;**** ****
;*************************************************************
;*************************************************************
;Global Server$ = "DOMINO1" ; Domino server (common) name
Global Server$ = "" ; Local server
Global SearchMatch.SEARCH_MATCH, ParameterCount
Global hNote.l, NoteID.l, pDB, hr
Global cDoc ; count documents in database
Global DFhandle
Global LFhandle
Global FullPath${#MAXPATH} = Space(#MAXPATH)
Global FileName${#MAXPATH} = Space(#MAXPATH)
Global ItemName${#MAXPATH} = Space(#MAXPATH)
Global ItemNameLen = Len(ItemName$)
Global NSFName${#MAX_PATH_LEN} = Space(#MAX_PATH_LEN)
Global Path${#MAX_PATH_LEN} = Space(#MAX_PATH_LEN)
;Global ViewID.l = 0
;Global ViewName${256}
Global StandardFile$ = "" ; set initial file+path to display
Global Pattern$ = ""
Global Pattern = 0 ; use the first of the three possible patterns as standard
Global File$ = ""
Global SubjectLine${#MAX_STRING_LEN} = Space(#MAX_STRING_LEN)
Global DeliveredDate${#MAXALPHATIMEDATE} = Space(#MAXALPHATIMEDATE)
Global FromLine${#MAX_STRING_LEN} = Space(#MAX_STRING_LEN)
;}
;-Import "C:\_Lotus_C_API_65\notesapi\lib\mswin32\notes.lib"
;{
Import "C:\_Lotus_C_API_65\notesapi\lib\mswin32\notes.lib"
NSFItemInfo(a.l, b.s, c.l, d.l, e.l, f.l, g.l) As "_NSFItemInfo@28"
NSFItemInfoNext(a.l, b.l, c.l, d.s, e.l, f.l, g.l, h.l, i.l) As "_NSFItemInfoNext@36"
NotesInit() As "_NotesInit@0"
NotesTerm() As "_NotesTerm@0"
; OSGetDataDirectory(a.l) As "_OSGetDataDirectory@4"
NSFDbClose(a.l) As "_NSFDbClose@4"
; NSFDbDirGet(a.l, b.s) As "_NSFDbDirGet@8"
; NSFDbInfoGet(a.l, b.l) As "_NSFDbInfoGet@8"
NSFDbOpen(a.l, *b) As "_NSFDbOpen@8"
; NSFDbPathGet(a.l, b.s, c.s) As "_NSFDbPathGet@12"
; NSFDbInfoParse(a.l, b.l, c.l, d.l) As "_NSFDbInfoParse@16"
NSFSearch(hDB.l, hFormula.l, ViewTitle.l, SearchFlags.l, NoteClassMask.l, Since.l, action_routine.l, EnumRoutineParameter.l, retUntil.l) As "_NSFSearch@36"
NSFNoteOpen(a.l, b.l, c.l, d.l) As "_NSFNoteOpen@16"
; NSFItemScan(a.l, b.l, c.l) As "_NSFItemScan@12"
NSFNoteClose(a.l) As "_NSFNoteClose@4"
; ***NOTE! NSFItemQuery in documentation only lists 9 parameters, use 10 and pass
; Block structure members as two separate parameters
NSFItemQuery(a.l, b.l, c.l, d.l, e.l, f.l, g.l, h.l, i.l, j.l) As "_NSFItemQuery@40"
OSLockObject(a.l) As "_OSLockObject@4"
OSUnlockObject(a.l) As "_OSUnlockObject@4"
NSFDbGetObjectSize(a.l, b.l, c.l, d.l, e.l, f.l) As "_NSFDbGetObjectSize@24"
OSPathNetConstruct(a.l, b.l, c.l, d.l) As "_OSPathNetConstruct@16"
NSGetServerList(a.l, b.l) As "_NSGetServerList@8"
ConvertTIMEDATEToText(a.l, b.l, c.l, d.l, e.l, f.l) As "_ConvertTIMEDATEToText@24"
NSFItemGetTextListEntry(a.l, b.s, c.l, d.l, e.l) As "_NSFItemGetTextListEntry@20"
NSFItemGetTextListEntries(a.l, b.s) As "_NSFItemGetTextListEntries@8"
NSFItemGetText(a.l, b.s, c.l, d.l) As "_NSFItemGetText@16"
EndImport
;}
Procedure ShowFileInfo(NoteID.l, *vB.BlockID)
Shared SubjectLine$
Protected AttachmentName$, *p.l
Protected dT, oID, cT, sl.l
Protected FileSize, FileClass, FilePriv
Print(NSFName$+",h"+RSet(Hex(NoteID),#NOTEID_LENGTH,"0")+",")
WriteString(#LOGFILE, NSFName$+",h"+RSet(Hex(NoteID),#NOTEID_LENGTH,"0")+",")
If *vB\hPool = 0 : ProcedureReturn : EndIf
*p = OSLockObject(*vB\hPool)
*p = *p + *vB\Block
If Not (*p)
MessageRequester("EXTREME DANGER, WILL ROBINSON!", "Warning, *p pointer is a big fat zero!")
OSUnlockObject(*vB\hPool)
ProcedureReturn
EndIf
sl = PeekW(*p+8) & $0000FFFF
Debug "sl: "+Hex(sl)
If (sl >= #MIN_STRING_LEN And sl <= #MAX_STRING_LEN)
AttachmentName$ = PeekS(*p+38, sl)
AttachmentName$ = RSet(AttachmentName$, Len(AttachmentName$)+1, Chr(34))
AttachmentName$ = LSet(AttachmentName$, Len(AttachmentName$)+1, Chr(34))
Print(AttachmentName$)
WriteString(#LOGFILE, AttachmentName$)
Else
Print("{INVALID LENGTH STRING}")
WriteString(#LOGFILE, "{INVALID LENGTH STRING}")
EndIf
Print(", "+Str(PeekL(*p+18)))
WriteString(#LOGFILE, ", "+Str(PeekL(*p+18)))
dT.l = 0
dT = PeekW(*p+2)
Debug "dT: "+Hex(dT)
oID = PeekL(*p+4)
Debug "oID: "+Hex(oID)
cT = PeekL(*p+12)
Debug "cT: "+Hex(cT)
NSFDbGetObjectSize(pDB, oID, dT, @FileSize, @FileClass, @FilePriv)
Print(", "+Str(FileSize))
WriteString(#LOGFILE, ", "+Str(FileSize))
Select cT
Case #NOCOMP
Print( ",None")
WriteString(#LOGFILE, ",None")
Case #HUFF
Print( ",Huffman")
WriteString(#LOGFILE, ",Huffman")
Case #LZ1
Print( ",LZ1")
WriteString(#LOGFILE, ",LZ1")
Default
Print( ",Unknown")
WriteString(#LOGFILE, ",Unknown")
EndSelect
OSUnlockObject(*vB\hPool)
Print(","+FromLine$)
WriteString(#LOGFILE, ","+FromLine$)
Print(","+DeliveredDate$)
WriteString(#LOGFILE, ","+DeliveredDate$)
PrintN(","+SubjectLine$)
WriteStringN(#LOGFILE, ","+SubjectLine$)
EndProcedure
Procedure GetSubject(hNote)
;********************************************************************
;* If we find at least one "$FILE" item, get the "Subject" field... *
;********************************************************************
Static NoteID.l = 0, ItemBlock.BlockID, ValueBlock.BlockID, DataType.l = 0, ValueBlockLen.l = 0
Static NameLengthPtr.l = 0, ItemFlagsPtr.l = 0, ValueDatatypePtr.l = 0
Protected *pPool
Protected hr
Protected ItemCount
Shared SubjectLine$
hr = NSFItemInfo( hNote, "Subject", 7, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
Debug "GetSubject> Datatype: "+Hex(DataType)
Debug "GetSubject> ValueBlockLen: "+Hex(ValueBlockLen)
Select Datatype
Case #TYPE_TEXT
Debug "GetSubject> #TYPE_TEXT"
hr = NSFItemGetText(hNote, "Subject", @SubjectLine$, SizeOf(SubjectLine$))
PokeB(@SubjectLine$+hr, 0)
Case #TYPE_TEXT_LIST
Debug "GetSubject> #TYPE_TEXT_LIST"
hr = NSFItemGetTextListEntry(hNote, "Subject", 0, @SubjectLine$, SizeOf(SubjectLine$)-1)
Debug "GetSubject> SizeOf(SubjectLine$):"+StrU(SizeOf(SubjectLine$),2)
PokeB(@SubjectLine$+hr, 0)
Debug "GetSubject> hr=NSFItemGetTextListEntry: "+Hex(hr)
Default
Debug "GetSubject> UNKNOWN_TYPE"
SubjectLine$ = "UNKNOWN_TYPE"
EndSelect
; strip out, then bound with double-quotes
SubjectLine$ = RemoveString(SubjectLine$, Chr(34))
SubjectLine$ = RSet(SubjectLine$, Len(SubjectLine$)+1, Chr(34))
SubjectLine$ = LSet(SubjectLine$, Len(SubjectLine$)+1, Chr(34))
Debug "GetSubject> SubjectLine$: "+SubjectLine$
EndProcedure
Procedure GetDeliveredDate(hNote)
;**************************************************************************
;* If we find at least one "$FILE" item, get the "DeliveredDate" field... *
;**************************************************************************
Static NoteID.l, ItemBlock.BlockID, ValueBlock.BlockID, DataType.l, ValueBlockLen.l
Static NameLengthPtr.l, ItemFlagsPtr.l, ValueDatatypePtr.l, TextBufferLen.l
Protected *pPool.l
Protected td.TFMT
Protected hr
With td
\Date = 0
\Time = 0
\Zone = 0
\Struc = 0
EndWith
hr = NSFItemInfo( hNote, "DeliveredDate", 13, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
Debug "GetDeliveredDate> NSFItemInfo('DeliveredDate') returned: "+Hex(hr)
; if error returned, use "PostedDate"...
If hr <> #NOERROR
hr = NSFItemInfo( hNote, "PostedDate", 10, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
Debug "GetDeliveredDate> NSFItemInfo('PostedDate') returned: "+Hex(hr)
EndIf
If ValueBlock\hPool
*pPool = OSLockObject(ValueBlock\hPool)
*pPool = *pPool + ValueBlock\Block
If Not (*pPool)
MessageRequester("EXTREME DANGER, WILL ROBINSON!", "Warning, *pPool pointer is a big fat zero!")
OSUnlockObject(ValueBlock\hPool)
ProcedureReturn
EndIf
If DataType = #TYPE_TIME_RANGE
*pPool + SizeOf(RANGE) ; skip over RANGE structure
EndIf
*pPool + SizeOf(WORD) ; skip over data type WORD
hr = ConvertTIMEDATEToText(#NUL, td, *pPool, @DeliveredDate$, #MAXALPHATIMEDATE, @TextBufferLen)
OSUnlockObject(ValueBlock\hPool)
PokeB(@DeliveredDate$+TextBufferLen, 0)
If hr = #NOERROR
DeliveredDate$ = RSet(DeliveredDate$, Len(DeliveredDate$)+1, Chr(34))
DeliveredDate$ = LSet(DeliveredDate$, Len(DeliveredDate$)+1, Chr(34))
Else
DeliveredDate$ = "INVALID OR BLANK DATE"
EndIf
Debug "GetDeliveredDate> DeliveredDate$: "+DeliveredDate$
EndIf
EndProcedure
Procedure GetFrom(hNote)
;*****************************************************************
;* If we find at least one "$FILE" item, get the "From" field... *
;*****************************************************************
Static NoteID.l = 0, ItemBlock.BlockID, ValueBlock.BlockID, DataType.l = 0, ValueBlockLen.l = 0
Static NameLengthPtr.l = 0, ItemFlagsPtr.l = 0, ValueDatatypePtr.l = 0
Protected *pPool
Protected hr, fCanonical, CommonNamePos, CommonNameLen, s$
hr = NSFItemInfo( hNote, "From", 4, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
Select Datatype
Case #TYPE_TEXT
Debug "GetFrom> #TYPE_TEXT"
hr = NSFItemGetText(hNote, "From", @FromLine$, SizeOf(FromLine$))
PokeB(@FromLine$+hr, 0)
Case #TYPE_TEXT_LIST
Debug "GetFrom> #TYPE_TEXT_LIST"
hr = NSFItemGetTextListEntry(hNote, "From", 0, @FromLine$, SizeOf(FromLine$)-1)
Debug "GetFrom> SizeOf(FromLine$):"+StrU(SizeOf(FromLine$),2)
PokeB(@FromLine$+hr, 0)
Debug "GetFrom> hr=NSFItemGetTextListEntry: "+Hex(hr)
Default
Debug "GetFrom> UNKNOWN_RECIPIENT"
FromLine$ = "UNKNOWN_RECIPIENT"
EndSelect
; Primitive Canonical Name stripper follows, which assumes "cn=" And "o=" both exist
; in the target string. Given "CN=My Name/O=My Organisation", will truncate to "My Name"
s$ = LCase(FromLine$) ; wish there was a case flag for the string functions - Fred?
fCanonical = 0 ; reset our "flag"
CommonNamePos = FindString(s$, "cn=", 1)
If (CommonNamePos) : fCanonical + 1 : EndIf
If FindString(s$, "/o=", 1) : fCanonical + 1 : EndIf
If fCanonical = 2 ; looks like we got a live one!
CommonNamePos = CommonNamePos + 3 ; skip over "cn="
CommonNameLen = FindString(s$, "/", CommonNamePos) - CommonNamePos
FromLine$ = Mid(FromLine$, CommonNamePos, CommonNameLen)
EndIf
; strip out, then bound with double-quotes
FromLine$ = RemoveString(FromLine$, Chr(34))
FromLine$ = RSet(FromLine$, Len(FromLine$)+1, Chr(34))
FromLine$ = LSet(FromLine$, Len(FromLine$)+1, Chr(34))
Debug "GetFrom> FromLine$: "+FromLine$
EndProcedure
Procedure NoteFound(*db_handle.l, *sm.SEARCH_MATCH, *summary_info)
Protected NoteID.l = 0, ItemBlock.BlockID, ValueBlock.BlockID, DataType.l = 0, ValueBlockLen.l = 0
Protected PreviousBlock.BlockID
Protected NameLengthPtr.l = 0, ItemFlagsPtr.l = 0, ValueDatatypePtr.l = 0
Protected hr
Shared hNote.l
Shared ItemName$
Shared ItemNameLen
NoteID.l = PeekL(*sm\ID\NoteID)
Debug ("Hex(NoteID)) = " + Hex(NoteID))
cDoc = cDoc + 1
hr = NSFNoteOpen(*db_handle.l, NoteID, 0, @hNote)
If hr <> #NOERROR
PrintN("Error opening note: 'h"+RSet(Hex(NoteID),#NOTEID_LENGTH,"0")+"'")
WriteStringN(#LOGFILE, "Error opening note: 'h"+RSet(Hex(NoteID),#NOTEID_LENGTH,"0")+"'")
Else
;====================================================================================
;= Note was opened okay, now look up any info we need before closing the note again =
;====================================================================================
; Just realised what may be a bug where it was not reporting multiple found items, could be due
; to the fact that I have "interrupted" the find chain for FILE$ items, by putting in calls to find
; the other item types ("Subject", DeliveredDate" and "From") in-between the initial NSFItemInfo()
; and the subsequent NSFItemInfoNext()! The whole thing can be done more elegantly by using arrays, etc
; but I can't be bothered - it works! Therefore, the following NSFItemInfo() is just to trigger
; the rest of the processing - it will be called again after the other 3 items are found...
hr = NSFItemInfo( hNote, "$FILE", 5, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
;***********************************************************************************************
;* If we find at least one "$FILE" item, also get the Subject, DeliveredDate and From items... *
;***********************************************************************************************
; Okay, there is at least one FILE$ item in this note. Find the other information we need before starting
; the loop to find all FILE$ items:
If hr = #NOERROR
GetSubject(hNote)
GetDeliveredDate(hNote)
GetFrom(hNote)
; Now prime the search for FILE$ items again...
hr = NSFItemInfo( hNote, "$FILE", 5, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
While hr = #NOERROR
ShowFileInfo(NoteID, @ValueBlock)
hr = NSFItemInfoNext( hNote, ItemBlock\hPool, ItemBlock\Block, "$FILE", 5, @ItemBlock, @DataType, @ValueBlock, @ValueBlockLen)
Wend
EndIf
EndIf
NSFNoteClose(hNote)
BlowThisJoint:
EndProcedure
Procedure FindServers()
;******************************************************
;* I'll make a decent version of this utility one day *
;* that will allow browsing of servers...one day... *
;******************************************************
; Structure WORD_ARRAY
; ww.w[0]
; EndStructure
Protected hServerList, i
Protected pServerList
Protected wServerCount.w
Dim ServerNameSizeArray.w(0)
Protected pServerNameSizeArray
Protected pServerNameStrings
Protected hr
; /* Get the list of available servers. Setting the first parameter
; To NULL gets a list of known servers on all ports.
; */
;
; sError = NSGetServerList( (char far *) NULL, &hServerList);
hr = NSGetServerList(#NUL, @hServerList)
;
; If (sError != NOERROR)
; {
; Return;
; }
If hr <> #NOERROR
PrintN("Error getting list of servers, aborting")
WriteStringN(#LOGFILE, "Error getting list of servers")
ProcedureReturn
EndIf
;
pServerList = OSLockObject(hServerList);
wServerCount = PeekW(pServerList)
Dim ServerNameStrings$(wServerCount)
;
pServerNameSizeArray = pServerList + SizeOf(WORD);
;
pServerNameStrings = pServerList + SizeOf(wServerCount) + ((wServerCount) * SizeOf(WORD));
;
; For (i=0; i<wServerCount; pServerNameStrings+=pServerNameSizeArray[i], i++)
For i=0 To wServerCount-1
; Debug PeekW(*pServerNameSizeArray\ww[i])
Debug PeekW(pServerNameSizeArray+(SizeOf(WORD)*i))
Debug PeekS(pServerNameStrings, PeekW(pServerNameSizeArray+(SizeOf(WORD)*i)))
; {
; memmove (szServerString, pServerNameStrings, pServerNameSizeArray[i]);
ServerNameStrings$(i) = PeekS(pServerNameStrings, PeekW(pServerNameSizeArray+(SizeOf(WORD)*i)))
; szServerString[pServerNameSizeArray[i]] = '\0';
; SendDlgItemMessage(hDlg, SERVLIST_LISTBOX, LB_ADDSTRING,
; (WORD) NULL,
; (LONG)(LPSTR) szServerString);
; }
pServerNameStrings = pServerNameStrings + PeekW(pServerNameSizeArray+(SizeOf(WORD)*i))
Next i
OSUnlockObject (hServerList);
; OSMemFree (hServerList);
EndProcedure
;-MAIN
;{
OpenConsole()
StandardFile$ = "C:\lotus\notes\data\ServerDir.txt" ; set initial file+path to display
Pattern$ = "Server NSF List (*.txt)|*.txt|All files (*.*)|*.*"
Pattern = 0 ; use the first of the three possible patterns as standard
File$ = OpenFileRequester("Select Directory Listing Input File", StandardFile$, Pattern$, Pattern)
DFhandle = ReadFile(#DIRFILE, File$)
If Not DFhandle
MessageRequester("ERROR", "Unable to open "+File$+" for input", 0)
Goto BlowTheJoint
EndIf
StandardFile$ = "C:\lotus\notes\data\AttachmentLog.csv" ; set initial file+path to display
Pattern$ = "Comma Separated (*.csv)|*.csv|Log (*.log)|*.log|All files (*.*)|*.*"
Pattern = 0 ; use the first of the three possible patterns as standard
File$ = SaveFileRequester("Select CSV Output File", StandardFile$, Pattern$, Pattern)
LFhandle = CreateFile(#LOGFILE, File$)
If Not LFhandle
MessageRequester("ERROR", "Unable to open "+File$+" for output", 0)
Goto BlowTheJoint
EndIf
WriteStringN(#LOGFILE, "FILENAME,NOTEID,ATTACHMENT,ORIGINAL-SIZE,COMPRESSED-SIZE,COMPRESSION,FROM,DATE,SUBJECT")
;-NotesInit()
Global fNotesInit = NotesInit()
Debug ("NotesInit() rc: " + Hex(fNotesInit))
If Not fNotesInit
MessageRequester("CRAP!", "Extreme error initialising NOTES, can't bear to go on")
Goto BlowTheJoint
EndIf
;FindServers()
While Not Eof(#DIRFILE)
cdoc = 0
FileName$ = ReadString(#DIRFILE)
Debug "FileName$: "+FileName$
Debug "FullPath$: "+FullPath$
hr = OSPathNetConstruct(#Null, @Server$, @FileName$, @FullPath$)
Debug "FullPath$: "+FullPath$
pDB = 0 : hr.l = NSFDbOpen(@FullPath$, @pDB.l)
Debug ( "NSFDbOpen rc: " + Hex(hr))
Debug ( "NSFDbOpen pointer: " + Hex(pDB))
; only display NSF filename, nothing else
NSFName$ = RemoveString(FullPath$, Server$+"!!", 1)
NSFName$ = GetFilePart(FullPath$)
If hr <> #NOERROR
PrintN("Error opening database: '"+NSFName$+"'")
WriteStringN(#LOGFILE, "Error opening database: '"+NSFName$+"'")
Goto ErrExit
EndIf
hr = NSFSearch(pDB, #Null, #Null, 0, #NOTE_CLASS_DOCUMENT, #Null, @NoteFound(), pDB, #Null)
Goto ErrExit
;-ErrExit:
ErrExit:
If pDB
hr = NSFDbClose(pDB) : Debug ( "NSFDbClose rc: " + Hex(hr))
If LFhandle : WriteStringN(#LOGFILE, NSFName$ + ",Document count," + Str(cDoc))
Else : PrintN(NSFName$ + ",Document Count," + Str(cDoc))
EndIf
EndIf
Wend
;-NotesTerm()
If Not fNotesInit : NotesTerm() : EndIf
;-BlowTheJoint:
BlowTheJoint:
CloseConsole()
End
;} END MAIN