How to sign NSF databases externally to Lotus Notes
[syntax="c"]#define SIMAN_NAME "Siman"
#define SIMAN_VERSION "Version 1.03a"
#define ERR_SIMAN_CANTINIT "Unable to Initialize Notes"
#define MSG_SIMAN_SUCCESS "Successfully signed database."
#define ERR_SIMAN_SERVERNAME "Unable to get server name"
#define ERR_SIMAN_DATABASENAME "Unable to get database name"
/* OS and C include files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Notes API include files */
#include <lapicinc.h>
#include <global.h>
#include <nsfnote.h>
#include <nsfdb.h>
#include <nsfsearc.h>
#include <osfile.h>
#include <osmem.h>
#include <names.h>
#include <nsferr.h>
#include <niferr.h>
#include <textlist.h>
#include <ods.h>
#include <odstypes.h>
#include <idtable.h>
#include <nsfdata.h>
#include <nif.h>
#include <agents.h>
#include <lapiplat.h>
#include <stdnames.h>
#include <addin.h>
#define SENSIBLEMSGLENGTH 1024
#define SENSIBLENAMELENGTH 256
/* Function prototypes */
extern STATUS far PASCAL fileActionNSFSearch (void *, SEARCH_MATCH *, ITEM_TABLE *);
extern void PrintTitle (DWORD dwItem, WORD wClass, BYTE *summary);
extern STATUS fileActionNSFOpen(void far *);
extern STATUS SignNoteItem (DBHANDLE, NOTEID);
extern STATUS SignAgent(DBHANDLE, NOTEID);
extern STATUS ProcessArgs (int argc, char *argv[]);
extern void PrintUsage( void );
extern void printSwitches(void);
extern void printVersion(void);
extern STATUS SayError(char *,STATUS);
extern STATUS ProcessActions(DBHANDLE hDb, char *);
//Gloabal Declarations and constants
#define STRING_LENGTH 256
FILE *dumpFile;
WORD NOTE_CLASS_MASK =(0);
WORD NIF_TYPE_MODIFIERS =(OPEN_REBUILD_INDEX);//- Throw away existing index and rebuild it from scratch.
WORD DB_TYPE_MODIFIERS =(FILE_DBANY);//(file type value) Find all .NSF, .NSG, or .NSH
WORD SEARCH_MODIFIERS =( FILE_DIRS + //find subdirectories
FILE_NOUPDIRS); //(search modifier) Search into subdirectories.
//WORD SEARCH_MODIFIERS =( FILE_NOUPDIRS); //(search modifier) Search into subdirectories.
int iLogLevel=0;
int iDBCount=0;
static BOOL bIncludeSubs = FALSE;
static BOOL bTest = FALSE;
static BOOL bLogToFile = FALSE;
static BOOL bLogLevel = FALSE;
typedef struct NSFEnum
{
char szServerName[SENSIBLENAMELENGTH];
DBHANDLE hDb;
HANDLE textlist_hdl;
WORD ListEntryCount;
} NSFEnum;[/syntax][syntax="c"]/****************************************************************************
PROGRAM: siman
FILE: siman.c
VERSION: 1.03a
SYNTAX siman <Server name> <database or directory name> [options]
options =
none - signs all design notes
-s - recurse subdirectories
-t - test do not actually sign
-f - <file name> Dump output to file name.
-l - <level> level of logging 1 to 10 1 being basic 10 being verbose
DESCRIPTION:
This signs all the deisgn Notes of databases in the specified directory on
the specified server. By specifying "" as the server this works
for local databases.
NEXT MODIFICATIONS:
build a directory list vs the db count
Set up proper devvelopment environment ie debug executed code if in debug with compiler directives
Set up platform independancy ie sizeof vars using LAPE ODSLENGTH ect
log to server log who last used the tool??
Provide configuration option at command line ie to use config db which sets all the flags instead of command line
Convert or write separate tool as notes addin? I do not beleive there is a great benfit
from converting to server addin task as each administrator can use this tool locally
from his or her workstation. One benefit is thet there is one central version of the exe
and a central logging database that can be overseen from a central point. Better for
future release enhancements to the exe as do not need to recall older version exe from admin users.
****************************************************************************/
/* SIMAN - specific include file */
#include "siman.h"
/************************************************************************
FUNCTION: NotesMain/Main
PURPOSE: Main Notes API routine
*************************************************************************/
LAPI_MAIN
{
//Local data declarations
USHORT usMode;
char szServer[STRING_LENGTH]={NULL}; //name of Lotus Domino Server
char szDirectory[STRING_LENGTH]={NULL}; //directory path
char fullNetPath[MAXPATH]; //full network path
DBHANDLE dirHandle; //handle for directory
STATUS error=NOERROR; // return status from API calls
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
char szErrorString[STRING_LENGTH];
char szTempString[STRING_LENGTH];
NSFEnum hNSFEnum;
void *textlist_ptr;
WORD list_entries, textlist_size;
WORD i;
DBHANDLE hDb;
LAPI_INIT(error);
if (error)
LAPI_INIT_ERROR;
// Assign dumpFile to stderr stream
dumpFile=stdout;
//Get the command line parameters that the user entered.
error=ProcessArgs(argc, argv);
if (error==NOERROR)
{
strcpy(szServer, argv[1]);
strcpy(szDirectory, argv[2]);
}
if (error)
{
LAPI_RETURN(NOERROR); //ProcessArgs already printed an error message
}
printVersion();
printSwitches();
//Compose the full network pathname to the directory.
if (error = OSPathNetConstruct(NULL, szServer, szDirectory,fullNetPath))
LAPI_RETURN (ERR(error));
// Open the directory.
if (error = NSFDbOpen (fullNetPath, &dirHandle))
LAPI_RETURN (ERR(error));
if (error = NSFDbModeGet (dirHandle, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
if (error = NSFDbInfoGet (dirHandle, szDBInfo))
{
OSLoadString(NULL, ERR(error),
szErrorString, STRING_LENGTH-1);
fprintf(stderr,"\nError: %s\n", szErrorString);
return (NOERROR);
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
//fprintf(stderr,"\nProcessing the '%s' database (%s)\n",fullNetPath,szDBTitle);
fprintf(stderr,"\n");
//if(error=fileActionNSFOpen(dirHandle))
//{
//OSLoadString(NULL, ERR(error),
//szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
//}
error=ProcessActions(dirHandle,fullNetPath);
if(error)
{
if(dirHandle!=NULLHANDLE)
{
if (error = NSFDbClose (dirHandle))
goto end;
}
}
goto end;
}
else if (usMode & DB_DIRECTORY) // hDB refers to a directory
{
if (strcmp(argv[1],(char *)"")==0)
fprintf(stderr,"\n'Searching the Notes data directory\n");
else
fprintf(stderr,"\nSearching the '%s' directory.\n\n", szDirectory);
}
textlist_size = 0;
if (error = ListAllocate( 0,
0,
FALSE,
&hNSFEnum.textlist_hdl,
&textlist_ptr,
&textlist_size))
return(ERR(error));
strcpy(hNSFEnum.szServerName,szServer);
hNSFEnum.hDb=dirHandle;
/* Call NSFSearch to find files in the directory. For each file found,
call an action routine.
What we do here is to specify NULL for Summary, and instead we use FILE_xxx flags to
find files. We are going to enumerate the files by passing the
file handle to the enum routine
When we call the enum routine .
At this point we call a set of functions which get a summary table for each database enumerated.
This is the technique to allow us to do actions like signing. Note use of getting $Path from summary table
this is used as we cannot open a note found in the summary szBuffer. We have to use the $Path item and use the string
value to pen the database by pathname.*/
error = NSFSearch (
dirHandle, //directory handle
NULLHANDLE, //selection formula
NULL, //title of view in formula
SEARCH_FILETYPE + //search for files
SEARCH_SUMMARY, //return a summary szBuffer
SEARCH_MODIFIERS +
DB_TYPE_MODIFIERS, //Search types, recurse ect
NULL, //starting date
fileActionNSFSearch,//call for each file found
&hNSFEnum, //argument to action routine
NULL); //returned ending date (unused)
if(error)
{
NSFDbClose (dirHandle);
fprintf(stderr,"\n!!Error encounted searching for databases.\n");
SayError ("error @ LAPI_MAIN:NSFSearch",ERR(error));
LAPI_RETURN (ERR(error));
}
textlist_ptr = OSLockObject(hNSFEnum.textlist_hdl);
list_entries = ListGetNumEntries(textlist_ptr, FALSE);
if (list_entries > 0)
{
printf("Processing file list\n");
for (i = 1; i < list_entries; i++)
{
char *pBuffer;
char szBuffer[MAXUSERNAME];
WORD BufferLength;
printf(".");
/* first entry is the cluster name */
error = ListGetText(textlist_ptr, FALSE, i, &pBuffer, &BufferLength);
{
strncpy(szBuffer, pBuffer, BufferLength);
szBuffer[BufferLength] = '\0';
//fprintf (stderr,"fullNetPath='%s'\n",szBuffer);
}
//What we do here is open the database
error = NSFDbOpenExtended( szBuffer,
DBOPEN_WITH_SCAN_LOCK+DBOPEN_FORCE_FIXUP+DBOPEN_FIXUP_FULL_NOTE_SCAN,
//DBOPEN_WITH_SCAN_LOCK,
NULLHANDLE,
NULL,
&hDb,
NULL,
NULL);
if(error!=NOERROR)
{
sprintf(szTempString,"\n\nfileActionNSFSearch:NSFDbOpen $Path=%s",fullNetPath);
SayError (szTempString,error);
goto end;
}
if (error = NSFDbModeGet (hDb, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
NSFDbClose (hDb);
//return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
//Sign Notes
error=ProcessActions(hDb,szBuffer);
if(error)
{
if(hDb!=NULLHANDLE)
{
if (error = NSFDbClose (hDb))
goto end;
}
}
}//End if
}//End for
}
end:
// Close the directory/database
if(dirHandle!=NULLHANDLE)
{
if (error = NSFDbClose (dirHandle))
LAPI_RETURN (ERR(error));
}else
dirHandle=NULLHANDLE;
if (error == NOERROR)
{
if (iDBCount == 0)fprintf(stderr,"\nFound %i database.\n",iDBCount+1);
else fprintf(stderr,"\nFound %i databases.\n",iDBCount);
printf("\nProgram completed successfully.\n");
}
// write dumpFile
fflush(dumpFile);
if (stdout!= dumpFile)
{
if( fclose( dumpFile ))
fprintf(stderr,"\nThe file 'data' was not closed\n" );
}
printf("\n");
// End of main routine.
LAPI_RETURN (NOERROR);
}
/************************************************************************
FUNCTION: PrintTitle
PURPOSE: print title and type of a design note
DESCRIPTION:
Prints the type of the design note (e.g. "Form") based on the
Class (e.g. NOTE_CLASS_FORM). Then it gets the title of the
form or view from the summary szBuffer and prints it.
*************************************************************************/
void PrintTitle (DWORD dwItem, WORD wClass, BYTE *summary)
{
char *szNoteType; ///e.g. "Form"
char *pItemValue; //initialized by NSFLocateSummaryValue
WORD Length, Type;
char szTitleString[DESIGN_NAME_MAX];
if (wClass & NOTE_CLASS_INFO)
szNoteType = "help-about";
else if (wClass & NOTE_CLASS_FORM)
szNoteType = "Form";
else if (wClass & NOTE_CLASS_VIEW)
szNoteType = "View";
else if (wClass & NOTE_CLASS_ICON)
szNoteType = "Icon";
else if (wClass & NOTE_CLASS_DESIGN)
szNoteType = "design collection";
else if (wClass & NOTE_CLASS_ACL)
szNoteType = "A.C.L.";
else if (wClass & NOTE_CLASS_HELP_INDEX)
szNoteType = "Notes Help";
else if (wClass & NOTE_CLASS_HELP)
szNoteType = "Database Help";
else if (wClass & NOTE_CLASS_FILTER)
szNoteType = "Macro";
else if (wClass & NOTE_CLASS_FIELD)
szNoteType = "Field"; //Notes 3.0 shared field
else if (wClass & NOTE_CLASS_REPLFORMULA)
szNoteType = "replication formula";
else
szNoteType = "unknown";
if (NSFLocateSummaryValue(summary,
ITEM_NAME_TEMPLATE_NAME, //"$TITLE"
&pItemValue,
&Length,
&Type))
{
if (TYPE_TEXT_LIST == Type)
{
WORD ListCount = 0;
//Get the count of items in this list
ODSReadMemory (&pItemValue, _WORD, &ListCount, 1);
//Get the length of the first item
ODSReadMemory (&pItemValue, _WORD, &Length, 1);
//Set the pointer to the first item in the list
pItemValue += (ListCount - 1) * ODSLength (_WORD);
}
if ((TYPE_TEXT == Type) || (TYPE_TEXT_LIST == Type))
{
//Make sure string is smaller than szBuffer!
if (Length >= DESIGN_NAME_MAX)
Length = DESIGN_NAME_MAX - 1;
memcpy (szTitleString, pItemValue, Length);
szTitleString[Length] = '\0';
}
else
strcpy (szTitleString, "unknown data type");
}
else
{
strcpy (szTitleString, "not available");
}
if (iLogLevel > 2 )
{
fprintf(stderr,"\tDesign Note %ld : Class = %s", dwItem+1, szNoteType);
fprintf(stderr,"\tTitle = '%s'", szTitleString);
}
return;
}
STATUS SignNoteItem(DBHANDLE *hDB, NOTEID noteID)
{
NOTEHANDLE noteHandle;
STATUS error;
//printf("\n Entered SignNoteItem \n");
//printf("\n Note Item is signed \n");
//Open the Note.
if (error = NSFNoteOpen (
hDB, //database handle
noteID, //Note ID
OPEN_EXPAND, // open flags
¬eHandle))
{
fprintf(stderr,"\n error oprning note \n");
SayError("error oprning note",error);
return (ERR(error));
}
//Sign the note
NSFNoteSign(noteHandle);
/*
switch(ERR(error))
{
case NOERROR:
{
printf("\nNote Item is signed = '%s'\n",ERR(error));
break;
}
case ERR_NOTE_NOT_SIGNED:
{
printf("\nNote Item is NOT signed\n");
break;
}
default:
{
return(ERR(error));
break;
}
}
*/
//NOERROR - The note or section signature was successfully verified.
//ERR_NOTE_NOT_SIGNED - The note or section has no signature.
if (error = NSFNoteUpdate(
noteHandle, UPDATE_FORCE))
return (ERR(error));
//close note
if (error = NSFNoteClose(noteHandle)) return (ERR(error));
if (iLogLevel>2)
fprintf(stderr,"\tnote %lX has been signed\n", noteID);
return(NOERROR);
}
STATUS SignAgent(void far *hDB, NOTEID noteID)
{
NOTEHANDLE noteHandle;
STATUS error;
//printf("\n Entered SignNoteItem \n");
//open the Note.
if (error = NSFNoteOpen (
hDB, //database handle
noteID, //Note ID
0, //open flags
¬eHandle))
{
fprintf(stderr,"\n error oprning note \n");
return (ERR(error));
}
//Sign the note
NSFNoteSign(noteHandle);
/*
switch(ERR(error))
{
case NOERROR:
{
printf("\nNote Item is signed = '%s'\n",ERR(error));
break;
}
case ERR_NOTE_NOT_SIGNED:
{
printf("\nNote Item is NOT signed\n");
break;
}
default:
{
return(ERR(error));
break;
}
}
*/
//NOERROR - The note or section signature was successfully verified.
//ERR_NOTE_NOT_SIGNED - The note or section has no signature.
if (error = NSFNoteUpdate(
noteHandle, UPDATE_FORCE))
return (ERR(error));
//close note.
if (error = NSFNoteClose(noteHandle)) return (ERR(error));
if (iLogLevel>2)
fprintf(stderr,"\tnote %lX has been signed\n", noteID);
return(NOERROR);
}
/************************************************************************
FUNCTION: fileActionNSFSearch
PURPOSE: routine called by NSFSearch for each file found
INPUTS:
The first argument to this function is the optional argument
that we supplied when we called NSFSearch. This is NULL as we do not use it
The second argument is supplied by NSFSearch. It is
a structure of information about the object that was found.
The third argument is also supplied by NSFSearch and is
the summary szBuffer for this object.
*************************************************************************/
STATUS LNPUBLIC fileActionNSFSearch(
NSFEnum *params,
SEARCH_MATCH far *pSearchMatch,
ITEM_TABLE *summary_info
)
{
WORD textlist_size;
STATUS error;
SEARCH_MATCH SearchMatch;
char *pItemName;
char *pItemValuePath;
char *pItemValueType;
WORD wLength,wType;
char szItemValueString[64];
BOOL bItemExists=FALSE;
char fullNetPath[MAXPATH]; //full network path
memcpy( (char*)&SearchMatch, (char*)pSearchMatch, sizeof(SEARCH_MATCH) );
/* Skip this object if it does not really match the search criteria (it
is now deleted or modified). This is not necessary for full searches,
but is shown here in case a starting date was used in the search. */
if (!(SearchMatch.SERetFlags & SE_FMATCH))
return (NOERROR);
pItemName="$Type",'\0'; //Create a null terminated string
//I found this item out by using finddbs
if (!(bItemExists=NSFLocateSummaryValue(
summary_info, //Pass in the summary bufer (ITEM_TABLE)
pItemName, //Pass in name of item to find
&pItemValueType, //Returned item value
&wLength, //Lenth of item Value
&wType //Returned item type (we know this is TEXT)
)))
{
fprintf(stderr,"\nItem: %s does not exist\n", pItemName);
return (NOERROR);
}
//We are going to test for type TEST anyway even though we know it is a text field
if (TYPE_TEXT == wType)
{
memcpy(szItemValueString, pItemValueType,wLength);
szItemValueString[wLength]='\0'; //Null terminate
}
if (iLogLevel>1)
// fprintf(stderr,"\n$Type = %s\n", szItemValueString);
//What we are doing here is testing wether database is a template assiged other databases
//Not yet!!!
//What we are going to do here is loop through summary table and get pathname from each database found.
//Note the summsry table contains the summary information of each database
pItemName="$Path",'\0'; //Create a null terminated string
//I found this item out by using finddbs
if (!(bItemExists=NSFLocateSummaryValue(
summary_info, //Pass in the summary bufer (ITEM_TABLE)
pItemName, //Pass in name of item to find
&pItemValuePath, //Returned item value
&wLength, //Lenth of item Value
&wType //Returned item type (we know this is TEXT)
)))
{
fprintf(stderr,"\nItem: %s does not exist\n", pItemName);
return (NOERROR);
}
//We are going to test for type TEST anyway even though we know it is a text field
if (TYPE_TEXT == wType)
{
memcpy(szItemValueString, pItemValuePath,wLength);
szItemValueString[wLength]='\0'; //Null terminate
}
if (iLogLevel>1)
//fprintf(stderr,"\n$Path = %s\n", szItemValueString);
//Compose the full network pathname to the directory.
iDBCount++;
//fprintf(stderr,"\nCount = %d\n", iDBCount);
if (error = OSPathNetConstruct(NULL, params->szServerName, szItemValueString,fullNetPath))
LAPI_RETURN (ERR(error));
//Add fullpath to list
ListAddEntry(params->textlist_hdl, FALSE,
&textlist_size,
params->ListEntryCount++,
fullNetPath,
(WORD) strlen(fullNetPath));
//fprintf(stderr,"\n'%s' is a directory, not a database file..Skipping directory!\n", szItemValueString);
return (NOERROR);
}
/************************************************************************
FUNCTION: fileActionNSFSearch
PURPOSE: routine called by NSFSearch for each file found
INPUTS:
The first argument to this function is the optional argument
that we supplied when we called NSFSearch. This is NULL as we do not use it
The second argument is supplied by NSFSearch. It is
a structure of information about the object that was found.
The third argument is also supplied by NSFSearch and is
the summary szBuffer for this object.
*************************************************************************/
STATUS fileActionNSFOpen(void far *hDB)
{
STATUS error;
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
char szErrorString[STRING_LENGTH];
HCOLLECTION hCollection;
COLLECTIONPOSITION CollPosition;
HANDLE hBuffer;
BYTE *pBuffer;
BYTE *pSummary;
DWORD dwEntriesFound, i;
ITEM_TABLE ItemTable;
WORD wClass;
NOTEID noteID;
BOOL bItemExists=FALSE;
USHORT usMode;
if (error = NSFDbModeGet (hDB, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
if (error = NSFDbInfoGet (hDB, szDBInfo))
{
OSLoadString(NULL, ERR(error),
szErrorString, STRING_LENGTH-1);
fprintf(stderr,"\nError: %s\n", szErrorString);
return (NOERROR);
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
if (iLogLevel>1)
fprintf(stderr,"\nPrinting design collection for '%s'\n", szDBTitle);
}
else if (usMode & DB_DIRECTORY) // hDB refers to a directory
{
//fprintf(stderr,"\n'%s' is a directory, not a database file..Skipping directory!\n", szItemValueString);
return(NOERROR);
}
//Open the special "design" collection, which contains an index of
//all nondata notes.
if (error = NIFOpenCollection(hDB,
hDB,
NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN,
NIF_TYPE_MODIFIERS ,
NULLHANDLE,
&hCollection,
NULL, NULL, NULL, NULL))
{
//Collection may not have been setup yet by the first user to
//open the file.
//fprintf(stderr,"Unable to open the design collection for '%s'\n", szDBTitle);
NSFDbClose (hDB);
return(ERR(error));
}
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 1;
//ReturnMask - Flags that control what information about the collection's entries will
//be returned. The information flags are defined in READ_MASK_xxx,
//and may be OR'ed together to combine functionailty.
//If more than one flag is requested, the order of the item's information in the szBuffer
//is the same order as the flag's bit numbers (i.e. flag bit 0 preceeds bit 1, then bit 2, etc).
if (error = NIFReadEntries(
hCollection, // handle to this collection
&CollPosition, // where to start in collection
NAVIGATE_CURRENT, // order to use when skipping
0L, // number to skip
NAVIGATE_NEXT, // order to use when reading
0xFFFFFFFF, // max number to read
READ_MASK_NOTEID |
READ_MASK_NOTECLASS | // read the note class
READ_MASK_SUMMARY, // and the summary szBuffer
&hBuffer, // handle to info szBuffer (return)
NULL, // length of info szBuffer (return)
NULL, // entries skipped (return)
&dwEntriesFound, // entries read (return)
NULL))
{
fprintf(stderr,"No entries found in design collection for '%s'.\n", szDBTitle);
NIFCloseCollection (hCollection);
NSFDbClose (hDB);
return(ERR(error));
}
//Check to make sure there was a szBuffer of information returned.
if (hBuffer == NULLHANDLE)
{
fprintf(stderr,"Empty szBuffer returned reading entries in design collection.\n");
NIFCloseCollection (hCollection);
NSFDbClose (hDB);
return (NOERROR);
}
pBuffer = (BYTE *) OSLockObject (hBuffer);
fprintf(stderr,"Found %ld design notes in '%s'.\n",dwEntriesFound, szDBTitle);
for (i = 0; i < dwEntriesFound; i++)
{
//if wewanted to get specific info that is unknown in size we would use memcpy
//however we know size of class, noteid and summary szBuffer
noteID = *(NOTEID*) pBuffer;
pBuffer += sizeof (NOTEID);
wClass = *(WORD*) pBuffer;
pBuffer += sizeof (WORD);
//Is it a an agent?
if (wClass & NOTE_CLASS_FILTER)
{
if (iLogLevel>1)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
SignAgent(&hDB,noteID);
}
else if (wClass & RRV_DELETED)
{
if (iLogLevel>1)
fprintf(stderr,"\nskipping deletion stub\n");
}
else
{
if (iLogLevel>1)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
fprintf(stderr,"\tsigned note %lX.\n", noteID);
}
ItemTable = *(ITEM_TABLE*) pBuffer;
//Remember where the start of this entry's summary is. Then advance
//the main pointer over the summary.
pSummary = pBuffer;
pBuffer += ItemTable.Length;
//Call PrintTitle to print the type and title of the design note.
PrintTitle (i, wClass, pSummary);
} //End of loop that processes each entry.
//Unlock the szBuffer returned from NIFReadEntries.
OSUnlockObject (hBuffer);
//Free the memory allocated by NIFReadEntries.
OSMemFree (hBuffer);
error = NIFCloseCollection(hCollection);
//End of subroutine./
return (NOERROR);
}
/************************************************************************
FUNCTION: PrintUsage
*************************************************************************/
void PrintUsage()
{
printVersion();
fprintf( stderr, "\n\nUSAGE : siman <servername> <database or directory name> [option]\n" );
fprintf( stderr, " ie. Hub/Acme names.nsf = sign the Domino Directory on the server\n");
fprintf( stderr, " ie. Hub/Acme global = sign the files in the 'global' folder on the server\n");
//fprintf( stderr, "NOTE. To specify 'no server' (local) use \"\" for <servername>\n");
//fprintf( stderr, " ie. \"\" help = sign files in the 'help' folder in the local data directory\n");
fprintf( stderr, " ie. \"\" \"\" = sign files on the 'local data directory\n");
//fprintf( stderr, " where as hub/acme \"\" = sign files in the server data directory\n");
fprintf( stderr, "\noption(s):\n");
fprintf( stderr, "-s recurse subdirectories (used if signing a folder).\n");
fprintf( stderr, "-f <file name> redirect output to file name.\n");
//fprintf( stderr, "\tie. '-f c:\\temp\\siman_log.txt'\n");
fprintf( stderr, "-l <level> log level for output 1 to 4. '1' is basic, '4' is verbose\n");
//fprintf( stderr, "\tie. '-l 2' would set log level to 2 \n");
fprintf( stderr, "-t test run ONLY (ie what would have happened) \n");
fprintf( stderr, "-d Database Types to search for (1=NSF, 2=NTF, 3=BOTH)\n");
//fprintf( stderr, "\tie. '-d 1' would mean sign .NSF files only\n");
fprintf( stderr, "-r Do NOT Discard and rebuild internal design view index\n");
fprintf( stderr, "-e Select design elements to sign (MANDATORY! have to choose atleast 1)\n");
fprintf( stderr, "\t'a'=Sign Agents\n");
fprintf( stderr, "\t'f'=Sign Forms\n");
fprintf( stderr, "\t'v'=Sign Views\n");
fprintf( stderr, "\t'r'=Sign Replication Formluas only\n");
fprintf( stderr, "\tie. '-e af' would mean sign both Formluas & Agents only");
return;
}
/************************************************************************
FUNCTION: ProcessArgs
INPUTS: argc, argv - directly from the command line
OUTPUTS: server - The server name to use
directory - The directory to look in
*************************************************************************/
STATUS ProcessArgs (int argc, char *argv[])
{
int iArgCount;
int iLevelIn;
char * copyL;
//int result;
if (argc < 3 )
{
//fprintf(stderr,"\nargc: %i\n",argc);
//fprintf(stderr,"\nargc: %s\n",argv[0]); //this prints put the application.exe name
//print out first argument if there are leading spaces ie no servername then the argument no. will be 2
//and we will need to trap this as we alsways want a minimum of three
PrintUsage();
return (PKG_ADDIN);
}
if (argv[0][0] == '""')
{
fprintf( stderr, "Error: <servername> cannot be a space use \"\".\n");
return (PKG_ADDIN);
}
// if options, read and intepret the arg list
if (argc > 3) //simple case: dump database
{
for (iArgCount = 3; iArgCount < argc; iArgCount++)
{
if ((argv[iArgCount][0] == '-') || (argv[iArgCount][0] == '/'))
{
if ((argv[iArgCount][1] == 's') || (argv[iArgCount][1] == 'S'))
{
SEARCH_MODIFIERS=(SEARCH_MODIFIERS + FILE_RECURSE);
bIncludeSubs = TRUE; //include subdirectories
//fprintf( stderr,"\n!!Error: -s is not available at this time.\n");
//return (PKG_ADDIN);
}
else if ((argv[iArgCount][1] == 't') || (argv[iArgCount][1] == 'T'))
{
bTest = TRUE; //Test only
//fprintf( stderr,"\nbTest= %i\n",bTest);
}
else if ((argv[iArgCount][1] == 'f') || (argv[iArgCount][1] == 'F'))
{
// -f option specified: next arg is filename
//make sure file name is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a dump file name.\n");
return (PKG_ADDIN);
}
// open the file and assign to dump file pointer
if ((dumpFile = freopen(argv[iArgCount+1],"w+",stderr)) == NULL)
{
fprintf( stderr,"\n!!Error: dump file '%s' could not be opened.\n",argv[iArgCount+1]);
return (PKG_ADDIN);
}
else
{ if (iLogLevel>3)
fprintf(stderr, "The dump file '%s' was opened\n",argv[iArgCount+1]);
bLogToFile = TRUE;
}
iArgCount++;
}
else if ((argv[iArgCount][1] == 'l') || (argv[iArgCount][1] == 'L'))
{
// -l option specified: next arg is level
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a level.\n");
return (PKG_ADDIN);
}
else
{
iLevelIn=atoi(argv[iArgCount+1]);
if (iLevelIn < 1 || iLevelIn >10)
{
fprintf( stderr,"\n!!Level must between 1 and 10. You entered %i\n",iLevelIn);
return (PKG_ADDIN);
}
//fprintf( stderr,"\n!!You entered %i\n",iLevelIn);
iArgCount++;
bLogLevel = TRUE;
iLogLevel=iLevelIn;
}
}
else if ((argv[iArgCount][1] == 'd') || (argv[iArgCount][1] == 'D'))
{
// -D option specified: next arg is database type
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a valid database type number.\n");
return (PKG_ADDIN);
}
else
{
switch(atoi(argv[iArgCount+1]))
{
case 1:
DB_TYPE_MODIFIERS =(FILE_DBANY); //(file type value) Find all .NSF, .NSG, or .NSH
//in the searched directory
break;
case 2:
DB_TYPE_MODIFIERS =(FILE_FTANY); //(file type value) Find all template (.NTF )
//in the searched directory
break;
case 3:
DB_TYPE_MODIFIERS =(FILE_DBDESIGN); //file type value) Find all databases and templates
//in the searched directory
break;
default:
{
DB_TYPE_MODIFIERS=(FILE_DBANY);
fprintf( stderr,"\n!!Error: Must supply a valid database type number.\n");
return (PKG_ADDIN);
}
}// End switch
iArgCount++;
}
}
else if ((argv[iArgCount][1] == 'r') || (argv[iArgCount][1] == 'R'))
{
NIF_TYPE_MODIFIERS =(OPEN_DO_NOT_CREATE);// - If collection object has not yet been created,
//do NOT create it automatically. Instead return a special internal error ERR_COLLECTION_NOT_CREATED.
}
else if ((argv[iArgCount][1] == 'e') || (argv[iArgCount][1] == 'E'))
{
// -E option specified: next arg's are
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply element types to sign.\n");
return (PKG_ADDIN);
}
else
{
//What we do here id loop through parameter to get all tokens
copyL = _strlwr( _strdup( argv[iArgCount+1] ) );
if(strchr( copyL, 'a' ))
NOTE_CLASS_MASK=NOTE_CLASS_FILTER;
if(strchr( copyL, 'f' ))
NOTE_CLASS_MASK+=NOTE_CLASS_FORM;
if(strchr( copyL, 'r' ))
NOTE_CLASS_MASK+=NOTE_CLASS_REPLFORMULA;
if(strchr( copyL, 'v' ))
NOTE_CLASS_MASK+=NOTE_CLASS_VIEW;
if(strchr( copyL, 'l' ))
NOTE_CLASS_MASK+=NOTE_CLASS_ACL;
if(strchr( copyL, 'n' ))
NOTE_CLASS_MASK+=NOTE_CLASS_INFO;
if(strchr( copyL, 'c' ))
NOTE_CLASS_MASK+=NOTE_CLASS_ICON;
if(strchr( copyL, 'i' ))
NOTE_CLASS_MASK+=NOTE_CLASS_HELP_INDEX;
if(strchr( copyL, 'h' ))
NOTE_CLASS_MASK+=NOTE_CLASS_HELP;
//printf( "NOTE_CLASS_MASK = %d\n", NOTE_CLASS_MASK);
iArgCount++;
}
}
else /* syntax error */
{
PrintUsage();
return (PKG_ADDIN);
}
}
else /* syntax error */
{
PrintUsage();
return (PKG_ADDIN);
}
}
}
return(NOERROR);
} // ProcessArgs
void printVersion(void)
{
fprintf(stderr,"\nSIMAN v1.03b by Calaman Consulting Limited (c)\n");
fprintf(stderr,"Last updated 04/07/2001\n");
fprintf(stderr,"email steve.robinson@calaman.com\n");
fprintf(stderr,"www.calaman.com\n");
fprintf(stderr,"(Notes API Version: %s)",NOTESAPI_VERSION);
fprintf(stderr,"\nNOTE. Tested up to r5.06a client and Server");
}
void printSwitches(void)
{
//printVersion();
if (iLogLevel>3)
{
if (bIncludeSubs)
fprintf(stderr,"\nSwitch -s is on\n");
if (bTest)
fprintf(stderr,"\nSwitch -t is on\n");
if (bLogToFile)
fprintf(stderr,"\nSwitch -f is on\n");
if (bLogLevel)
fprintf(stderr,"\nSwitch -l is on\n");
}
}
/******************************************************************/
/******************************************************************/
/*********** SayError **************************************/
/******************************************************************/
/******************************************************************/
STATUS SayError (char *msgText,STATUS error)
{
char MessageText [SENSIBLEMSGLENGTH], ErrorString [SENSIBLEMSGLENGTH];
strcpy (MessageText, "\nSIMAN Says: ");
strcat(MessageText,msgText);
OSLoadString(NULLHANDLE, ERR(error), ErrorString, sizeof(ErrorString)-1);
strcat (MessageText, ErrorString);
//AddInLogMessageText (MessageText, NOERROR);
fprintf(stderr,MessageText);
return(0);
}
/******************************************************************/
/******************************************************************/
/*********** ProcessActions **************************************/
/******************************************************************/
/******************************************************************/
STATUS ProcessActions(DBHANDLE hDb,char *szFullPathName)
{
STATUS error;
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
HCOLLECTION hCollection;
COLLECTIONPOSITION CollPosition;
HANDLE hBuffer;
BYTE *pBuffer;
//BYTE *pSummary;
DWORD dwEntriesFound, i;
ITEM_TABLE ItemTable;
WORD wClass,wMinorVer,wMajorVer;
NOTEID noteID;
BOOL bItemExists=FALSE;
//char szErrorString[STRING_LENGTH];
if (error = NSFDbInfoGet (hDb, szDBInfo))
{
//OSLoadString(NULL, ERR(error),
//szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
return (ERR(error));
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
//Open the special "design" collection, which contains an index of
//all nondata notes.
/* Output major and minor version numbers */
if (error = NSFDbMajorMinorVersionGet(hDb, &wMajorVer, &wMinorVer))
return(ERR(error));
//Open collection of notes
if (error = NIFOpenCollection(hDb,
hDb,
//NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN+NOTE_CLASS_SINGLE_INSTANCE,
NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN,
NIF_TYPE_MODIFIERS ,
NULLHANDLE,
&hCollection,
NULL, NULL, NULL, NULL))
{
//Collection may not have been setup yet by the first user to open the file.
//OSLoadString(NULL, ERR(error),szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
if(error==ERR_COLLECTION_NOT_CREATED)
fprintf(stderr,"\nfor Database '%s' (%s)Collection does not exist, and was not created",szFullPathName,szDBTitle);
else
{
SayError ("error @ fileActionNSFSearch:NIFOpenCollection",ERR(error));
fprintf(stderr," for Database '%s' (%s)\n",szFullPathName,szDBTitle);
}
//fprintf(stderr,"Cannot open collection for '%s' (%s). Probably due to the fact that the database is corrupted?\n",szFullPathName,szDBTitle);
//NSFDbClose (hDb);
return(ERR(error));
}
//error=NIFUpdateCollection(hCollection);
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 1;
//ReturnMask - Flags that control what information about the collection's entries will
//be returned. The information flags are defined in READ_MASK_xxx,
//and may be OR'ed together to combine functionailty.
//If more than one flag is requested, the order of the item's information in the szBuffer
//is the same order as the flag's bit numbers (i.e. flag bit 0 preceeds bit 1, then bit 2, etc).
if (error = NIFReadEntries(
hCollection, // handle to this collection
&CollPosition, // where to start in collection
NAVIGATE_CURRENT, // order to use when skipping
0L, // number to skip
NAVIGATE_NEXT, // order to use when reading
0xFFFFFFFF, // max number to read
READ_MASK_NOTEID | // read the noteID
READ_MASK_NOTECLASS | // read the note class
READ_MASK_SUMMARY, // and the summary szBuffer
&hBuffer, // handle to info szBuffer (return)
NULL, // length of info szBuffer (return)
NULL, // entries skipped (return)
&dwEntriesFound, // entries read (return)
NULL))
{
fprintf(stderr,"No entries found in design collection for '%s'.\n", szDBTitle);
NIFCloseCollection (hCollection);
//NSFDbClose (hDb);
return(ERR(error));
}
//Check to make sure there was a szBuffer of information returned.
if (hBuffer == NULLHANDLE)
{
fprintf(stderr,"Empty szBuffer returned reading entries in design collection.\n");
NIFCloseCollection (hCollection);
NSFDbClose (hDb);
return (NOERROR);
}
pBuffer = (BYTE *) OSLockObject (hBuffer);
fprintf(stderr,"\nFound %ld design notes in %s (%s)\n",dwEntriesFound, szFullPathName,szDBTitle);
fprintf(stderr,"Major ver: %d, minor ver: %d\n", wMajorVer, wMinorVer);
for (i = 0; i < dwEntriesFound; i++)
{
//if wewanted to get specific info that is unknown in size we would use memcpy
//however we know size of class, noteid and summary szBuffer
noteID = *(NOTEID*) pBuffer;
pBuffer += sizeof (NOTEID);
wClass = *(WORD*) pBuffer;
pBuffer += sizeof (WORD);
//Call PrintTitle to print the type and title of the design note.
//Is it a an agent?
if (wClass & NOTE_CLASS_MASK & NOTE_CLASS_FILTER)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing Agent note %lX.", noteID);
if (!bTest)
{
SignAgent(hDb,noteID);
}
}//END FILTER
if (wClass & RRV_DELETED)
{ PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\nskipping deletion stub\n");
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_FORM)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_VIEW)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_FIELD)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_REPLFORMULA)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
/*
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_ACL)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
*/
/*
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_INFO)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_ICON)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_HELP_INDEX)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
*/
ItemTable = *(ITEM_TABLE*) pBuffer;
//Remember where the start of this entry's summary is. Then advance
//the main pointer over the summary.
//pSummary = pBuffer;
pBuffer += ItemTable.Length;
} //End of loop that processes each entry.
//Unlock the szBuffer returned from NIFReadEntries.
OSUnlockObject (hBuffer);
//Free the memory allocated by NIFReadEntries.
OSMemFree (hBuffer);
error = NIFCloseCollection(hCollection);
return(0);
}[/syntax]Lotus Notes C-API source code. How to sign NSF databases externally to Lotus Notes. Sign databases without using the administration client.
#define SIMAN_VERSION "Version 1.03a"
#define ERR_SIMAN_CANTINIT "Unable to Initialize Notes"
#define MSG_SIMAN_SUCCESS "Successfully signed database."
#define ERR_SIMAN_SERVERNAME "Unable to get server name"
#define ERR_SIMAN_DATABASENAME "Unable to get database name"
/* OS and C include files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Notes API include files */
#include <lapicinc.h>
#include <global.h>
#include <nsfnote.h>
#include <nsfdb.h>
#include <nsfsearc.h>
#include <osfile.h>
#include <osmem.h>
#include <names.h>
#include <nsferr.h>
#include <niferr.h>
#include <textlist.h>
#include <ods.h>
#include <odstypes.h>
#include <idtable.h>
#include <nsfdata.h>
#include <nif.h>
#include <agents.h>
#include <lapiplat.h>
#include <stdnames.h>
#include <addin.h>
#define SENSIBLEMSGLENGTH 1024
#define SENSIBLENAMELENGTH 256
/* Function prototypes */
extern STATUS far PASCAL fileActionNSFSearch (void *, SEARCH_MATCH *, ITEM_TABLE *);
extern void PrintTitle (DWORD dwItem, WORD wClass, BYTE *summary);
extern STATUS fileActionNSFOpen(void far *);
extern STATUS SignNoteItem (DBHANDLE, NOTEID);
extern STATUS SignAgent(DBHANDLE, NOTEID);
extern STATUS ProcessArgs (int argc, char *argv[]);
extern void PrintUsage( void );
extern void printSwitches(void);
extern void printVersion(void);
extern STATUS SayError(char *,STATUS);
extern STATUS ProcessActions(DBHANDLE hDb, char *);
//Gloabal Declarations and constants
#define STRING_LENGTH 256
FILE *dumpFile;
WORD NOTE_CLASS_MASK =(0);
WORD NIF_TYPE_MODIFIERS =(OPEN_REBUILD_INDEX);//- Throw away existing index and rebuild it from scratch.
WORD DB_TYPE_MODIFIERS =(FILE_DBANY);//(file type value) Find all .NSF, .NSG, or .NSH
WORD SEARCH_MODIFIERS =( FILE_DIRS + //find subdirectories
FILE_NOUPDIRS); //(search modifier) Search into subdirectories.
//WORD SEARCH_MODIFIERS =( FILE_NOUPDIRS); //(search modifier) Search into subdirectories.
int iLogLevel=0;
int iDBCount=0;
static BOOL bIncludeSubs = FALSE;
static BOOL bTest = FALSE;
static BOOL bLogToFile = FALSE;
static BOOL bLogLevel = FALSE;
typedef struct NSFEnum
{
char szServerName[SENSIBLENAMELENGTH];
DBHANDLE hDb;
HANDLE textlist_hdl;
WORD ListEntryCount;
} NSFEnum;[/syntax][syntax="c"]/****************************************************************************
PROGRAM: siman
FILE: siman.c
VERSION: 1.03a
SYNTAX siman <Server name> <database or directory name> [options]
options =
none - signs all design notes
-s - recurse subdirectories
-t - test do not actually sign
-f - <file name> Dump output to file name.
-l - <level> level of logging 1 to 10 1 being basic 10 being verbose
DESCRIPTION:
This signs all the deisgn Notes of databases in the specified directory on
the specified server. By specifying "" as the server this works
for local databases.
NEXT MODIFICATIONS:
build a directory list vs the db count
Set up proper devvelopment environment ie debug executed code if in debug with compiler directives
Set up platform independancy ie sizeof vars using LAPE ODSLENGTH ect
log to server log who last used the tool??
Provide configuration option at command line ie to use config db which sets all the flags instead of command line
Convert or write separate tool as notes addin? I do not beleive there is a great benfit
from converting to server addin task as each administrator can use this tool locally
from his or her workstation. One benefit is thet there is one central version of the exe
and a central logging database that can be overseen from a central point. Better for
future release enhancements to the exe as do not need to recall older version exe from admin users.
****************************************************************************/
/* SIMAN - specific include file */
#include "siman.h"
/************************************************************************
FUNCTION: NotesMain/Main
PURPOSE: Main Notes API routine
*************************************************************************/
LAPI_MAIN
{
//Local data declarations
USHORT usMode;
char szServer[STRING_LENGTH]={NULL}; //name of Lotus Domino Server
char szDirectory[STRING_LENGTH]={NULL}; //directory path
char fullNetPath[MAXPATH]; //full network path
DBHANDLE dirHandle; //handle for directory
STATUS error=NOERROR; // return status from API calls
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
char szErrorString[STRING_LENGTH];
char szTempString[STRING_LENGTH];
NSFEnum hNSFEnum;
void *textlist_ptr;
WORD list_entries, textlist_size;
WORD i;
DBHANDLE hDb;
LAPI_INIT(error);
if (error)
LAPI_INIT_ERROR;
// Assign dumpFile to stderr stream
dumpFile=stdout;
//Get the command line parameters that the user entered.
error=ProcessArgs(argc, argv);
if (error==NOERROR)
{
strcpy(szServer, argv[1]);
strcpy(szDirectory, argv[2]);
}
if (error)
{
LAPI_RETURN(NOERROR); //ProcessArgs already printed an error message
}
printVersion();
printSwitches();
//Compose the full network pathname to the directory.
if (error = OSPathNetConstruct(NULL, szServer, szDirectory,fullNetPath))
LAPI_RETURN (ERR(error));
// Open the directory.
if (error = NSFDbOpen (fullNetPath, &dirHandle))
LAPI_RETURN (ERR(error));
if (error = NSFDbModeGet (dirHandle, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
if (error = NSFDbInfoGet (dirHandle, szDBInfo))
{
OSLoadString(NULL, ERR(error),
szErrorString, STRING_LENGTH-1);
fprintf(stderr,"\nError: %s\n", szErrorString);
return (NOERROR);
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
//fprintf(stderr,"\nProcessing the '%s' database (%s)\n",fullNetPath,szDBTitle);
fprintf(stderr,"\n");
//if(error=fileActionNSFOpen(dirHandle))
//{
//OSLoadString(NULL, ERR(error),
//szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
//}
error=ProcessActions(dirHandle,fullNetPath);
if(error)
{
if(dirHandle!=NULLHANDLE)
{
if (error = NSFDbClose (dirHandle))
goto end;
}
}
goto end;
}
else if (usMode & DB_DIRECTORY) // hDB refers to a directory
{
if (strcmp(argv[1],(char *)"")==0)
fprintf(stderr,"\n'Searching the Notes data directory\n");
else
fprintf(stderr,"\nSearching the '%s' directory.\n\n", szDirectory);
}
textlist_size = 0;
if (error = ListAllocate( 0,
0,
FALSE,
&hNSFEnum.textlist_hdl,
&textlist_ptr,
&textlist_size))
return(ERR(error));
strcpy(hNSFEnum.szServerName,szServer);
hNSFEnum.hDb=dirHandle;
/* Call NSFSearch to find files in the directory. For each file found,
call an action routine.
What we do here is to specify NULL for Summary, and instead we use FILE_xxx flags to
find files. We are going to enumerate the files by passing the
file handle to the enum routine
When we call the enum routine .
At this point we call a set of functions which get a summary table for each database enumerated.
This is the technique to allow us to do actions like signing. Note use of getting $Path from summary table
this is used as we cannot open a note found in the summary szBuffer. We have to use the $Path item and use the string
value to pen the database by pathname.*/
error = NSFSearch (
dirHandle, //directory handle
NULLHANDLE, //selection formula
NULL, //title of view in formula
SEARCH_FILETYPE + //search for files
SEARCH_SUMMARY, //return a summary szBuffer
SEARCH_MODIFIERS +
DB_TYPE_MODIFIERS, //Search types, recurse ect
NULL, //starting date
fileActionNSFSearch,//call for each file found
&hNSFEnum, //argument to action routine
NULL); //returned ending date (unused)
if(error)
{
NSFDbClose (dirHandle);
fprintf(stderr,"\n!!Error encounted searching for databases.\n");
SayError ("error @ LAPI_MAIN:NSFSearch",ERR(error));
LAPI_RETURN (ERR(error));
}
textlist_ptr = OSLockObject(hNSFEnum.textlist_hdl);
list_entries = ListGetNumEntries(textlist_ptr, FALSE);
if (list_entries > 0)
{
printf("Processing file list\n");
for (i = 1; i < list_entries; i++)
{
char *pBuffer;
char szBuffer[MAXUSERNAME];
WORD BufferLength;
printf(".");
/* first entry is the cluster name */
error = ListGetText(textlist_ptr, FALSE, i, &pBuffer, &BufferLength);
{
strncpy(szBuffer, pBuffer, BufferLength);
szBuffer[BufferLength] = '\0';
//fprintf (stderr,"fullNetPath='%s'\n",szBuffer);
}
//What we do here is open the database
error = NSFDbOpenExtended( szBuffer,
DBOPEN_WITH_SCAN_LOCK+DBOPEN_FORCE_FIXUP+DBOPEN_FIXUP_FULL_NOTE_SCAN,
//DBOPEN_WITH_SCAN_LOCK,
NULLHANDLE,
NULL,
&hDb,
NULL,
NULL);
if(error!=NOERROR)
{
sprintf(szTempString,"\n\nfileActionNSFSearch:NSFDbOpen $Path=%s",fullNetPath);
SayError (szTempString,error);
goto end;
}
if (error = NSFDbModeGet (hDb, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
NSFDbClose (hDb);
//return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
//Sign Notes
error=ProcessActions(hDb,szBuffer);
if(error)
{
if(hDb!=NULLHANDLE)
{
if (error = NSFDbClose (hDb))
goto end;
}
}
}//End if
}//End for
}
end:
// Close the directory/database
if(dirHandle!=NULLHANDLE)
{
if (error = NSFDbClose (dirHandle))
LAPI_RETURN (ERR(error));
}else
dirHandle=NULLHANDLE;
if (error == NOERROR)
{
if (iDBCount == 0)fprintf(stderr,"\nFound %i database.\n",iDBCount+1);
else fprintf(stderr,"\nFound %i databases.\n",iDBCount);
printf("\nProgram completed successfully.\n");
}
// write dumpFile
fflush(dumpFile);
if (stdout!= dumpFile)
{
if( fclose( dumpFile ))
fprintf(stderr,"\nThe file 'data' was not closed\n" );
}
printf("\n");
// End of main routine.
LAPI_RETURN (NOERROR);
}
/************************************************************************
FUNCTION: PrintTitle
PURPOSE: print title and type of a design note
DESCRIPTION:
Prints the type of the design note (e.g. "Form") based on the
Class (e.g. NOTE_CLASS_FORM). Then it gets the title of the
form or view from the summary szBuffer and prints it.
*************************************************************************/
void PrintTitle (DWORD dwItem, WORD wClass, BYTE *summary)
{
char *szNoteType; ///e.g. "Form"
char *pItemValue; //initialized by NSFLocateSummaryValue
WORD Length, Type;
char szTitleString[DESIGN_NAME_MAX];
if (wClass & NOTE_CLASS_INFO)
szNoteType = "help-about";
else if (wClass & NOTE_CLASS_FORM)
szNoteType = "Form";
else if (wClass & NOTE_CLASS_VIEW)
szNoteType = "View";
else if (wClass & NOTE_CLASS_ICON)
szNoteType = "Icon";
else if (wClass & NOTE_CLASS_DESIGN)
szNoteType = "design collection";
else if (wClass & NOTE_CLASS_ACL)
szNoteType = "A.C.L.";
else if (wClass & NOTE_CLASS_HELP_INDEX)
szNoteType = "Notes Help";
else if (wClass & NOTE_CLASS_HELP)
szNoteType = "Database Help";
else if (wClass & NOTE_CLASS_FILTER)
szNoteType = "Macro";
else if (wClass & NOTE_CLASS_FIELD)
szNoteType = "Field"; //Notes 3.0 shared field
else if (wClass & NOTE_CLASS_REPLFORMULA)
szNoteType = "replication formula";
else
szNoteType = "unknown";
if (NSFLocateSummaryValue(summary,
ITEM_NAME_TEMPLATE_NAME, //"$TITLE"
&pItemValue,
&Length,
&Type))
{
if (TYPE_TEXT_LIST == Type)
{
WORD ListCount = 0;
//Get the count of items in this list
ODSReadMemory (&pItemValue, _WORD, &ListCount, 1);
//Get the length of the first item
ODSReadMemory (&pItemValue, _WORD, &Length, 1);
//Set the pointer to the first item in the list
pItemValue += (ListCount - 1) * ODSLength (_WORD);
}
if ((TYPE_TEXT == Type) || (TYPE_TEXT_LIST == Type))
{
//Make sure string is smaller than szBuffer!
if (Length >= DESIGN_NAME_MAX)
Length = DESIGN_NAME_MAX - 1;
memcpy (szTitleString, pItemValue, Length);
szTitleString[Length] = '\0';
}
else
strcpy (szTitleString, "unknown data type");
}
else
{
strcpy (szTitleString, "not available");
}
if (iLogLevel > 2 )
{
fprintf(stderr,"\tDesign Note %ld : Class = %s", dwItem+1, szNoteType);
fprintf(stderr,"\tTitle = '%s'", szTitleString);
}
return;
}
STATUS SignNoteItem(DBHANDLE *hDB, NOTEID noteID)
{
NOTEHANDLE noteHandle;
STATUS error;
//printf("\n Entered SignNoteItem \n");
//printf("\n Note Item is signed \n");
//Open the Note.
if (error = NSFNoteOpen (
hDB, //database handle
noteID, //Note ID
OPEN_EXPAND, // open flags
¬eHandle))
{
fprintf(stderr,"\n error oprning note \n");
SayError("error oprning note",error);
return (ERR(error));
}
//Sign the note
NSFNoteSign(noteHandle);
/*
switch(ERR(error))
{
case NOERROR:
{
printf("\nNote Item is signed = '%s'\n",ERR(error));
break;
}
case ERR_NOTE_NOT_SIGNED:
{
printf("\nNote Item is NOT signed\n");
break;
}
default:
{
return(ERR(error));
break;
}
}
*/
//NOERROR - The note or section signature was successfully verified.
//ERR_NOTE_NOT_SIGNED - The note or section has no signature.
if (error = NSFNoteUpdate(
noteHandle, UPDATE_FORCE))
return (ERR(error));
//close note
if (error = NSFNoteClose(noteHandle)) return (ERR(error));
if (iLogLevel>2)
fprintf(stderr,"\tnote %lX has been signed\n", noteID);
return(NOERROR);
}
STATUS SignAgent(void far *hDB, NOTEID noteID)
{
NOTEHANDLE noteHandle;
STATUS error;
//printf("\n Entered SignNoteItem \n");
//open the Note.
if (error = NSFNoteOpen (
hDB, //database handle
noteID, //Note ID
0, //open flags
¬eHandle))
{
fprintf(stderr,"\n error oprning note \n");
return (ERR(error));
}
//Sign the note
NSFNoteSign(noteHandle);
/*
switch(ERR(error))
{
case NOERROR:
{
printf("\nNote Item is signed = '%s'\n",ERR(error));
break;
}
case ERR_NOTE_NOT_SIGNED:
{
printf("\nNote Item is NOT signed\n");
break;
}
default:
{
return(ERR(error));
break;
}
}
*/
//NOERROR - The note or section signature was successfully verified.
//ERR_NOTE_NOT_SIGNED - The note or section has no signature.
if (error = NSFNoteUpdate(
noteHandle, UPDATE_FORCE))
return (ERR(error));
//close note.
if (error = NSFNoteClose(noteHandle)) return (ERR(error));
if (iLogLevel>2)
fprintf(stderr,"\tnote %lX has been signed\n", noteID);
return(NOERROR);
}
/************************************************************************
FUNCTION: fileActionNSFSearch
PURPOSE: routine called by NSFSearch for each file found
INPUTS:
The first argument to this function is the optional argument
that we supplied when we called NSFSearch. This is NULL as we do not use it
The second argument is supplied by NSFSearch. It is
a structure of information about the object that was found.
The third argument is also supplied by NSFSearch and is
the summary szBuffer for this object.
*************************************************************************/
STATUS LNPUBLIC fileActionNSFSearch(
NSFEnum *params,
SEARCH_MATCH far *pSearchMatch,
ITEM_TABLE *summary_info
)
{
WORD textlist_size;
STATUS error;
SEARCH_MATCH SearchMatch;
char *pItemName;
char *pItemValuePath;
char *pItemValueType;
WORD wLength,wType;
char szItemValueString[64];
BOOL bItemExists=FALSE;
char fullNetPath[MAXPATH]; //full network path
memcpy( (char*)&SearchMatch, (char*)pSearchMatch, sizeof(SEARCH_MATCH) );
/* Skip this object if it does not really match the search criteria (it
is now deleted or modified). This is not necessary for full searches,
but is shown here in case a starting date was used in the search. */
if (!(SearchMatch.SERetFlags & SE_FMATCH))
return (NOERROR);
pItemName="$Type",'\0'; //Create a null terminated string
//I found this item out by using finddbs
if (!(bItemExists=NSFLocateSummaryValue(
summary_info, //Pass in the summary bufer (ITEM_TABLE)
pItemName, //Pass in name of item to find
&pItemValueType, //Returned item value
&wLength, //Lenth of item Value
&wType //Returned item type (we know this is TEXT)
)))
{
fprintf(stderr,"\nItem: %s does not exist\n", pItemName);
return (NOERROR);
}
//We are going to test for type TEST anyway even though we know it is a text field
if (TYPE_TEXT == wType)
{
memcpy(szItemValueString, pItemValueType,wLength);
szItemValueString[wLength]='\0'; //Null terminate
}
if (iLogLevel>1)
// fprintf(stderr,"\n$Type = %s\n", szItemValueString);
//What we are doing here is testing wether database is a template assiged other databases
//Not yet!!!
//What we are going to do here is loop through summary table and get pathname from each database found.
//Note the summsry table contains the summary information of each database
pItemName="$Path",'\0'; //Create a null terminated string
//I found this item out by using finddbs
if (!(bItemExists=NSFLocateSummaryValue(
summary_info, //Pass in the summary bufer (ITEM_TABLE)
pItemName, //Pass in name of item to find
&pItemValuePath, //Returned item value
&wLength, //Lenth of item Value
&wType //Returned item type (we know this is TEXT)
)))
{
fprintf(stderr,"\nItem: %s does not exist\n", pItemName);
return (NOERROR);
}
//We are going to test for type TEST anyway even though we know it is a text field
if (TYPE_TEXT == wType)
{
memcpy(szItemValueString, pItemValuePath,wLength);
szItemValueString[wLength]='\0'; //Null terminate
}
if (iLogLevel>1)
//fprintf(stderr,"\n$Path = %s\n", szItemValueString);
//Compose the full network pathname to the directory.
iDBCount++;
//fprintf(stderr,"\nCount = %d\n", iDBCount);
if (error = OSPathNetConstruct(NULL, params->szServerName, szItemValueString,fullNetPath))
LAPI_RETURN (ERR(error));
//Add fullpath to list
ListAddEntry(params->textlist_hdl, FALSE,
&textlist_size,
params->ListEntryCount++,
fullNetPath,
(WORD) strlen(fullNetPath));
//fprintf(stderr,"\n'%s' is a directory, not a database file..Skipping directory!\n", szItemValueString);
return (NOERROR);
}
/************************************************************************
FUNCTION: fileActionNSFSearch
PURPOSE: routine called by NSFSearch for each file found
INPUTS:
The first argument to this function is the optional argument
that we supplied when we called NSFSearch. This is NULL as we do not use it
The second argument is supplied by NSFSearch. It is
a structure of information about the object that was found.
The third argument is also supplied by NSFSearch and is
the summary szBuffer for this object.
*************************************************************************/
STATUS fileActionNSFOpen(void far *hDB)
{
STATUS error;
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
char szErrorString[STRING_LENGTH];
HCOLLECTION hCollection;
COLLECTIONPOSITION CollPosition;
HANDLE hBuffer;
BYTE *pBuffer;
BYTE *pSummary;
DWORD dwEntriesFound, i;
ITEM_TABLE ItemTable;
WORD wClass;
NOTEID noteID;
BOOL bItemExists=FALSE;
USHORT usMode;
if (error = NSFDbModeGet (hDB, &usMode))
{
fprintf(stderr,"\n!!Error: unable to get database mode.\n");
return(ERR(error));
}
if (usMode & DB_LOADED) //hDB refers to a normal database file
{
if (error = NSFDbInfoGet (hDB, szDBInfo))
{
OSLoadString(NULL, ERR(error),
szErrorString, STRING_LENGTH-1);
fprintf(stderr,"\nError: %s\n", szErrorString);
return (NOERROR);
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
if (iLogLevel>1)
fprintf(stderr,"\nPrinting design collection for '%s'\n", szDBTitle);
}
else if (usMode & DB_DIRECTORY) // hDB refers to a directory
{
//fprintf(stderr,"\n'%s' is a directory, not a database file..Skipping directory!\n", szItemValueString);
return(NOERROR);
}
//Open the special "design" collection, which contains an index of
//all nondata notes.
if (error = NIFOpenCollection(hDB,
hDB,
NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN,
NIF_TYPE_MODIFIERS ,
NULLHANDLE,
&hCollection,
NULL, NULL, NULL, NULL))
{
//Collection may not have been setup yet by the first user to
//open the file.
//fprintf(stderr,"Unable to open the design collection for '%s'\n", szDBTitle);
NSFDbClose (hDB);
return(ERR(error));
}
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 1;
//ReturnMask - Flags that control what information about the collection's entries will
//be returned. The information flags are defined in READ_MASK_xxx,
//and may be OR'ed together to combine functionailty.
//If more than one flag is requested, the order of the item's information in the szBuffer
//is the same order as the flag's bit numbers (i.e. flag bit 0 preceeds bit 1, then bit 2, etc).
if (error = NIFReadEntries(
hCollection, // handle to this collection
&CollPosition, // where to start in collection
NAVIGATE_CURRENT, // order to use when skipping
0L, // number to skip
NAVIGATE_NEXT, // order to use when reading
0xFFFFFFFF, // max number to read
READ_MASK_NOTEID |
READ_MASK_NOTECLASS | // read the note class
READ_MASK_SUMMARY, // and the summary szBuffer
&hBuffer, // handle to info szBuffer (return)
NULL, // length of info szBuffer (return)
NULL, // entries skipped (return)
&dwEntriesFound, // entries read (return)
NULL))
{
fprintf(stderr,"No entries found in design collection for '%s'.\n", szDBTitle);
NIFCloseCollection (hCollection);
NSFDbClose (hDB);
return(ERR(error));
}
//Check to make sure there was a szBuffer of information returned.
if (hBuffer == NULLHANDLE)
{
fprintf(stderr,"Empty szBuffer returned reading entries in design collection.\n");
NIFCloseCollection (hCollection);
NSFDbClose (hDB);
return (NOERROR);
}
pBuffer = (BYTE *) OSLockObject (hBuffer);
fprintf(stderr,"Found %ld design notes in '%s'.\n",dwEntriesFound, szDBTitle);
for (i = 0; i < dwEntriesFound; i++)
{
//if wewanted to get specific info that is unknown in size we would use memcpy
//however we know size of class, noteid and summary szBuffer
noteID = *(NOTEID*) pBuffer;
pBuffer += sizeof (NOTEID);
wClass = *(WORD*) pBuffer;
pBuffer += sizeof (WORD);
//Is it a an agent?
if (wClass & NOTE_CLASS_FILTER)
{
if (iLogLevel>1)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
SignAgent(&hDB,noteID);
}
else if (wClass & RRV_DELETED)
{
if (iLogLevel>1)
fprintf(stderr,"\nskipping deletion stub\n");
}
else
{
if (iLogLevel>1)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
fprintf(stderr,"\tsigned note %lX.\n", noteID);
}
ItemTable = *(ITEM_TABLE*) pBuffer;
//Remember where the start of this entry's summary is. Then advance
//the main pointer over the summary.
pSummary = pBuffer;
pBuffer += ItemTable.Length;
//Call PrintTitle to print the type and title of the design note.
PrintTitle (i, wClass, pSummary);
} //End of loop that processes each entry.
//Unlock the szBuffer returned from NIFReadEntries.
OSUnlockObject (hBuffer);
//Free the memory allocated by NIFReadEntries.
OSMemFree (hBuffer);
error = NIFCloseCollection(hCollection);
//End of subroutine./
return (NOERROR);
}
/************************************************************************
FUNCTION: PrintUsage
*************************************************************************/
void PrintUsage()
{
printVersion();
fprintf( stderr, "\n\nUSAGE : siman <servername> <database or directory name> [option]\n" );
fprintf( stderr, " ie. Hub/Acme names.nsf = sign the Domino Directory on the server\n");
fprintf( stderr, " ie. Hub/Acme global = sign the files in the 'global' folder on the server\n");
//fprintf( stderr, "NOTE. To specify 'no server' (local) use \"\" for <servername>\n");
//fprintf( stderr, " ie. \"\" help = sign files in the 'help' folder in the local data directory\n");
fprintf( stderr, " ie. \"\" \"\" = sign files on the 'local data directory\n");
//fprintf( stderr, " where as hub/acme \"\" = sign files in the server data directory\n");
fprintf( stderr, "\noption(s):\n");
fprintf( stderr, "-s recurse subdirectories (used if signing a folder).\n");
fprintf( stderr, "-f <file name> redirect output to file name.\n");
//fprintf( stderr, "\tie. '-f c:\\temp\\siman_log.txt'\n");
fprintf( stderr, "-l <level> log level for output 1 to 4. '1' is basic, '4' is verbose\n");
//fprintf( stderr, "\tie. '-l 2' would set log level to 2 \n");
fprintf( stderr, "-t test run ONLY (ie what would have happened) \n");
fprintf( stderr, "-d Database Types to search for (1=NSF, 2=NTF, 3=BOTH)\n");
//fprintf( stderr, "\tie. '-d 1' would mean sign .NSF files only\n");
fprintf( stderr, "-r Do NOT Discard and rebuild internal design view index\n");
fprintf( stderr, "-e Select design elements to sign (MANDATORY! have to choose atleast 1)\n");
fprintf( stderr, "\t'a'=Sign Agents\n");
fprintf( stderr, "\t'f'=Sign Forms\n");
fprintf( stderr, "\t'v'=Sign Views\n");
fprintf( stderr, "\t'r'=Sign Replication Formluas only\n");
fprintf( stderr, "\tie. '-e af' would mean sign both Formluas & Agents only");
return;
}
/************************************************************************
FUNCTION: ProcessArgs
INPUTS: argc, argv - directly from the command line
OUTPUTS: server - The server name to use
directory - The directory to look in
*************************************************************************/
STATUS ProcessArgs (int argc, char *argv[])
{
int iArgCount;
int iLevelIn;
char * copyL;
//int result;
if (argc < 3 )
{
//fprintf(stderr,"\nargc: %i\n",argc);
//fprintf(stderr,"\nargc: %s\n",argv[0]); //this prints put the application.exe name
//print out first argument if there are leading spaces ie no servername then the argument no. will be 2
//and we will need to trap this as we alsways want a minimum of three
PrintUsage();
return (PKG_ADDIN);
}
if (argv[0][0] == '""')
{
fprintf( stderr, "Error: <servername> cannot be a space use \"\".\n");
return (PKG_ADDIN);
}
// if options, read and intepret the arg list
if (argc > 3) //simple case: dump database
{
for (iArgCount = 3; iArgCount < argc; iArgCount++)
{
if ((argv[iArgCount][0] == '-') || (argv[iArgCount][0] == '/'))
{
if ((argv[iArgCount][1] == 's') || (argv[iArgCount][1] == 'S'))
{
SEARCH_MODIFIERS=(SEARCH_MODIFIERS + FILE_RECURSE);
bIncludeSubs = TRUE; //include subdirectories
//fprintf( stderr,"\n!!Error: -s is not available at this time.\n");
//return (PKG_ADDIN);
}
else if ((argv[iArgCount][1] == 't') || (argv[iArgCount][1] == 'T'))
{
bTest = TRUE; //Test only
//fprintf( stderr,"\nbTest= %i\n",bTest);
}
else if ((argv[iArgCount][1] == 'f') || (argv[iArgCount][1] == 'F'))
{
// -f option specified: next arg is filename
//make sure file name is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a dump file name.\n");
return (PKG_ADDIN);
}
// open the file and assign to dump file pointer
if ((dumpFile = freopen(argv[iArgCount+1],"w+",stderr)) == NULL)
{
fprintf( stderr,"\n!!Error: dump file '%s' could not be opened.\n",argv[iArgCount+1]);
return (PKG_ADDIN);
}
else
{ if (iLogLevel>3)
fprintf(stderr, "The dump file '%s' was opened\n",argv[iArgCount+1]);
bLogToFile = TRUE;
}
iArgCount++;
}
else if ((argv[iArgCount][1] == 'l') || (argv[iArgCount][1] == 'L'))
{
// -l option specified: next arg is level
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a level.\n");
return (PKG_ADDIN);
}
else
{
iLevelIn=atoi(argv[iArgCount+1]);
if (iLevelIn < 1 || iLevelIn >10)
{
fprintf( stderr,"\n!!Level must between 1 and 10. You entered %i\n",iLevelIn);
return (PKG_ADDIN);
}
//fprintf( stderr,"\n!!You entered %i\n",iLevelIn);
iArgCount++;
bLogLevel = TRUE;
iLogLevel=iLevelIn;
}
}
else if ((argv[iArgCount][1] == 'd') || (argv[iArgCount][1] == 'D'))
{
// -D option specified: next arg is database type
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply a valid database type number.\n");
return (PKG_ADDIN);
}
else
{
switch(atoi(argv[iArgCount+1]))
{
case 1:
DB_TYPE_MODIFIERS =(FILE_DBANY); //(file type value) Find all .NSF, .NSG, or .NSH
//in the searched directory
break;
case 2:
DB_TYPE_MODIFIERS =(FILE_FTANY); //(file type value) Find all template (.NTF )
//in the searched directory
break;
case 3:
DB_TYPE_MODIFIERS =(FILE_DBDESIGN); //file type value) Find all databases and templates
//in the searched directory
break;
default:
{
DB_TYPE_MODIFIERS=(FILE_DBANY);
fprintf( stderr,"\n!!Error: Must supply a valid database type number.\n");
return (PKG_ADDIN);
}
}// End switch
iArgCount++;
}
}
else if ((argv[iArgCount][1] == 'r') || (argv[iArgCount][1] == 'R'))
{
NIF_TYPE_MODIFIERS =(OPEN_DO_NOT_CREATE);// - If collection object has not yet been created,
//do NOT create it automatically. Instead return a special internal error ERR_COLLECTION_NOT_CREATED.
}
else if ((argv[iArgCount][1] == 'e') || (argv[iArgCount][1] == 'E'))
{
// -E option specified: next arg's are
//make sure level is supplied
if (argc < iArgCount + 2)
{
//fprintf( stderr,"\n!!iargCount == %i\n",iArgCount);
fprintf( stderr,"\n!!Error: Must supply element types to sign.\n");
return (PKG_ADDIN);
}
else
{
//What we do here id loop through parameter to get all tokens
copyL = _strlwr( _strdup( argv[iArgCount+1] ) );
if(strchr( copyL, 'a' ))
NOTE_CLASS_MASK=NOTE_CLASS_FILTER;
if(strchr( copyL, 'f' ))
NOTE_CLASS_MASK+=NOTE_CLASS_FORM;
if(strchr( copyL, 'r' ))
NOTE_CLASS_MASK+=NOTE_CLASS_REPLFORMULA;
if(strchr( copyL, 'v' ))
NOTE_CLASS_MASK+=NOTE_CLASS_VIEW;
if(strchr( copyL, 'l' ))
NOTE_CLASS_MASK+=NOTE_CLASS_ACL;
if(strchr( copyL, 'n' ))
NOTE_CLASS_MASK+=NOTE_CLASS_INFO;
if(strchr( copyL, 'c' ))
NOTE_CLASS_MASK+=NOTE_CLASS_ICON;
if(strchr( copyL, 'i' ))
NOTE_CLASS_MASK+=NOTE_CLASS_HELP_INDEX;
if(strchr( copyL, 'h' ))
NOTE_CLASS_MASK+=NOTE_CLASS_HELP;
//printf( "NOTE_CLASS_MASK = %d\n", NOTE_CLASS_MASK);
iArgCount++;
}
}
else /* syntax error */
{
PrintUsage();
return (PKG_ADDIN);
}
}
else /* syntax error */
{
PrintUsage();
return (PKG_ADDIN);
}
}
}
return(NOERROR);
} // ProcessArgs
void printVersion(void)
{
fprintf(stderr,"\nSIMAN v1.03b by Calaman Consulting Limited (c)\n");
fprintf(stderr,"Last updated 04/07/2001\n");
fprintf(stderr,"email steve.robinson@calaman.com\n");
fprintf(stderr,"www.calaman.com\n");
fprintf(stderr,"(Notes API Version: %s)",NOTESAPI_VERSION);
fprintf(stderr,"\nNOTE. Tested up to r5.06a client and Server");
}
void printSwitches(void)
{
//printVersion();
if (iLogLevel>3)
{
if (bIncludeSubs)
fprintf(stderr,"\nSwitch -s is on\n");
if (bTest)
fprintf(stderr,"\nSwitch -t is on\n");
if (bLogToFile)
fprintf(stderr,"\nSwitch -f is on\n");
if (bLogLevel)
fprintf(stderr,"\nSwitch -l is on\n");
}
}
/******************************************************************/
/******************************************************************/
/*********** SayError **************************************/
/******************************************************************/
/******************************************************************/
STATUS SayError (char *msgText,STATUS error)
{
char MessageText [SENSIBLEMSGLENGTH], ErrorString [SENSIBLEMSGLENGTH];
strcpy (MessageText, "\nSIMAN Says: ");
strcat(MessageText,msgText);
OSLoadString(NULLHANDLE, ERR(error), ErrorString, sizeof(ErrorString)-1);
strcat (MessageText, ErrorString);
//AddInLogMessageText (MessageText, NOERROR);
fprintf(stderr,MessageText);
return(0);
}
/******************************************************************/
/******************************************************************/
/*********** ProcessActions **************************************/
/******************************************************************/
/******************************************************************/
STATUS ProcessActions(DBHANDLE hDb,char *szFullPathName)
{
STATUS error;
char szDBInfo[NSF_INFO_SIZE];
char szDBTitle[NSF_INFO_SIZE];
HCOLLECTION hCollection;
COLLECTIONPOSITION CollPosition;
HANDLE hBuffer;
BYTE *pBuffer;
//BYTE *pSummary;
DWORD dwEntriesFound, i;
ITEM_TABLE ItemTable;
WORD wClass,wMinorVer,wMajorVer;
NOTEID noteID;
BOOL bItemExists=FALSE;
//char szErrorString[STRING_LENGTH];
if (error = NSFDbInfoGet (hDb, szDBInfo))
{
//OSLoadString(NULL, ERR(error),
//szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
return (ERR(error));
}
NSFDbInfoParse (szDBInfo, INFOPARSE_TITLE, szDBTitle, NSF_INFO_SIZE-1);
//Open the special "design" collection, which contains an index of
//all nondata notes.
/* Output major and minor version numbers */
if (error = NSFDbMajorMinorVersionGet(hDb, &wMajorVer, &wMinorVer))
return(ERR(error));
//Open collection of notes
if (error = NIFOpenCollection(hDb,
hDb,
//NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN+NOTE_CLASS_SINGLE_INSTANCE,
NOTE_ID_SPECIAL+NOTE_CLASS_DESIGN,
NIF_TYPE_MODIFIERS ,
NULLHANDLE,
&hCollection,
NULL, NULL, NULL, NULL))
{
//Collection may not have been setup yet by the first user to open the file.
//OSLoadString(NULL, ERR(error),szErrorString, STRING_LENGTH-1);
//fprintf(stderr,"\nError: %s\n", szErrorString);
if(error==ERR_COLLECTION_NOT_CREATED)
fprintf(stderr,"\nfor Database '%s' (%s)Collection does not exist, and was not created",szFullPathName,szDBTitle);
else
{
SayError ("error @ fileActionNSFSearch:NIFOpenCollection",ERR(error));
fprintf(stderr," for Database '%s' (%s)\n",szFullPathName,szDBTitle);
}
//fprintf(stderr,"Cannot open collection for '%s' (%s). Probably due to the fact that the database is corrupted?\n",szFullPathName,szDBTitle);
//NSFDbClose (hDb);
return(ERR(error));
}
//error=NIFUpdateCollection(hCollection);
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 1;
//ReturnMask - Flags that control what information about the collection's entries will
//be returned. The information flags are defined in READ_MASK_xxx,
//and may be OR'ed together to combine functionailty.
//If more than one flag is requested, the order of the item's information in the szBuffer
//is the same order as the flag's bit numbers (i.e. flag bit 0 preceeds bit 1, then bit 2, etc).
if (error = NIFReadEntries(
hCollection, // handle to this collection
&CollPosition, // where to start in collection
NAVIGATE_CURRENT, // order to use when skipping
0L, // number to skip
NAVIGATE_NEXT, // order to use when reading
0xFFFFFFFF, // max number to read
READ_MASK_NOTEID | // read the noteID
READ_MASK_NOTECLASS | // read the note class
READ_MASK_SUMMARY, // and the summary szBuffer
&hBuffer, // handle to info szBuffer (return)
NULL, // length of info szBuffer (return)
NULL, // entries skipped (return)
&dwEntriesFound, // entries read (return)
NULL))
{
fprintf(stderr,"No entries found in design collection for '%s'.\n", szDBTitle);
NIFCloseCollection (hCollection);
//NSFDbClose (hDb);
return(ERR(error));
}
//Check to make sure there was a szBuffer of information returned.
if (hBuffer == NULLHANDLE)
{
fprintf(stderr,"Empty szBuffer returned reading entries in design collection.\n");
NIFCloseCollection (hCollection);
NSFDbClose (hDb);
return (NOERROR);
}
pBuffer = (BYTE *) OSLockObject (hBuffer);
fprintf(stderr,"\nFound %ld design notes in %s (%s)\n",dwEntriesFound, szFullPathName,szDBTitle);
fprintf(stderr,"Major ver: %d, minor ver: %d\n", wMajorVer, wMinorVer);
for (i = 0; i < dwEntriesFound; i++)
{
//if wewanted to get specific info that is unknown in size we would use memcpy
//however we know size of class, noteid and summary szBuffer
noteID = *(NOTEID*) pBuffer;
pBuffer += sizeof (NOTEID);
wClass = *(WORD*) pBuffer;
pBuffer += sizeof (WORD);
//Call PrintTitle to print the type and title of the design note.
//Is it a an agent?
if (wClass & NOTE_CLASS_MASK & NOTE_CLASS_FILTER)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing Agent note %lX.", noteID);
if (!bTest)
{
SignAgent(hDb,noteID);
}
}//END FILTER
if (wClass & RRV_DELETED)
{ PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\nskipping deletion stub\n");
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_FORM)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_VIEW)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_FIELD)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_REPLFORMULA)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
/*
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_ACL)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
*/
/*
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_INFO)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_ICON)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
if(wClass & NOTE_CLASS_MASK & NOTE_CLASS_HELP_INDEX)
{
PrintTitle (i, wClass, pBuffer);
if (iLogLevel>2)
fprintf(stderr,"\n\tProcessing note %lX.", noteID);
if (!bTest)
if (iLogLevel>2)
SignNoteItem(hDb,noteID);
}
*/
ItemTable = *(ITEM_TABLE*) pBuffer;
//Remember where the start of this entry's summary is. Then advance
//the main pointer over the summary.
//pSummary = pBuffer;
pBuffer += ItemTable.Length;
} //End of loop that processes each entry.
//Unlock the szBuffer returned from NIFReadEntries.
OSUnlockObject (hBuffer);
//Free the memory allocated by NIFReadEntries.
OSMemFree (hBuffer);
error = NIFCloseCollection(hCollection);
return(0);
}[/syntax]Lotus Notes C-API source code. How to sign NSF databases externally to Lotus Notes. Sign databases without using the administration client.