Lotus Notes
Volume Number: | | 12
|
Issue Number: | | 9
|
Column Tag: | | Communication And Collaboration
|
Driving Lotus Notes From an Application
Find API-ness in the land of the Lotus-Eaters
By Rick Gansler
Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.
Lotus Notes is much more than a groupware or email program; it is a client/server document-oriented groupware database with a powerful API library that can be used to create standalone platform-independent C programs. With the introduction of Notes Release 4 for Mac OS 68K and PowerPC, Lotus has created a Mac client application that improves on Release 3 in innumerable ways. One such improvement is the inclusion of the Notes C API for Mac OS.
This article discusses the Notes C API and its implementation for the Mac OS. A sample API program is listed and explained. The sample program demonstrates how to export a Notes database in a form that can be compiled as a Newton Book for the Apple Newton PDA. Also discussed are the Notes C++ API and Vendor Independent Messaging (VIM) SDK, which will soon be available for the Mac OS.
Introducing Lotus Notes
Lotus Notes enables teams of people to communicate with each other, collaborate on shared documents, and generate custom workflow applications. The teams may all be connected to the same local area network, or may be connected via modem or remote access bridges.
Information is generally stored on a scaleable Notes server in the form of an encrypted relational database, in which various types of data can be stored. Users can create their own forms, providing a customized view of the data. Fax, voice mail, and pager gateways enhance the portability of the data. Interfaces to the Internet and legacy databases on mainframes further increase the scope of data portability.
The end user sees Notes as a window called the workspace (Figure 1) containing icons that represent databases. These databases may be stored on a Notes server or on a local disk or file server. Opening a database presents the user with a view (Figure 2) of the database, and a list of documents (Figure 3). A view may be thought of as the sorted result of a search. Each database may have one or more views, and always has a default view. Opening a document displays a form through which the documents fields (or items) are presented.
Figure 1. Notes client application workspace
Figure 2. Notes client application database view
Whats So Special About Notes?
Notes shows its uniqueness in four areas: database replication, database design, cross-platform support, and application development.
Replication resembles synchronization of files, or mirroring of Web and FTP sites, only more powerful. Replication is bi-directional, and supports update, insertion, and deletion. It enables the same database to be stored on multiple servers and then updated so that all databases have the same contents, structure, and access controls. Databases can optionally be selectively replicated; this can be applied at the document or even at the field level. Field-level replication is especially useful when replicating over a modem, since less data needs to be transferred than when doing document-level replication. Having databases replicated across multiple servers is useful, since those servers can be distributed across organizations or time zones, which distributes the load of user activity among the different servers. Notes maintains a replication history, keeping track of when data was updated, as well as what the source of that data was, thus speeding future replications.
Figure 3. Notes client application document
Using data access hooks into Notes, a Notes database can be synchronized with a legacy database. This feature enables an IS department to keep data and some applications on a mainframe (for example), yet still allow Notes users to access and modify that data from a desktop computer.
Databases can be designed using templates and custom forms, a number of runtime views, @functions (which take arguments, perform logical actions on data, and return a result), Navigators (which add a GUI with buttons and links on top of the database), Agents (scheduled and event-driven macros), HotSpots (like buttons), DocLinks (referring to any Notes document in any Notes database), and URLs (referring to a Web page via the InterNotes server).
Lotus Notes is truly cross-plaform, and is supported on Mac OS (client only), Windows 16-bit (client only), Windows 32-bit, OS/2 Warp, NetWare (server only), and many UNIX platforms including Solaris, HP/UX, and AIX. The Dec Alpha platform running Windows NT and Dec UNIX will soon be added to this list. A Notes client can access any Notes server, regardless of platform, using a variety of network protocols. For the most part, Notes for all platforms have identical functionality and an identical user interface.
Notes Application Development
There are two ways to accomplish Notes application development. The first is to use LotusScript, a cross-platform object-oriented event-driven interpreted language, which can be used in Notes as well as in other Lotus products. LotusScript is interpreted and cannot be run standalone. The second method is to create standalone programs using the Notes C API (or any of the other APIs, such as Notes C++ API, that are built on top of the C API); such standalones run independently of the Notes application, yet have access to Notes services. Just as different programming languages exist, each designed for a particular niche, Notes has multiple development options for programmers having different levels of experience and different development needs. Since the C API for Mac OS has only very recently been released, not all of the Notes API Toolkit development environments are available for Macintosh. Figure 4 shows the different environments, their level of object orientation, and their target audience.
Visual Basic Extensions (VBX) and OLE2 Extensions (OCX) are not available for Mac OS, so their Notes implementations cannot be made available either. The HiTest C API is an object-based (but not C++) layer built on top of the C API. Lotus has not yet determined if HiTest will be ported to Mac OS. Without HiTest on Mac, there can be no HiTest Glue, which is implemented as a VBX to provide Visual Basic programmers with controls that interact with Notes.
(Note that the C API can also be used to build code that is executed by Notes, for example to make import/export filters, menu add-in modules, and server add-in tasks. The subject, however, is beyond the scope of this article.)
Figure 4. Notes programming methods
Notes Architecture
The Notes C API is Notes. The API is a large set of Notes functions that have been exposed for third-party developers to use. This means that the API is as important to Lotus as it is to developers; Lotus Notes is itself written using many of the same API calls that are available in the Notes API.
Admittedly, some parts of the Notes client and server applications use functions that are not available in the API; so an API programmer cannot write a program that does everything that the Notes client does. Recall, for example, the workspace window (Figure 1). This windows list of user databases and their icons is stored in a database called desktop.nsf; but Notes API calls cannot access this list.
Just the other way, though, some tasks available through the API cannot be accomplished through the Notes client applications user interface. For example, if a user has a document but doesnt have the form with which the document was created, it may not be possible to view all fields in that document using the Notes client. (A form defines what fields can be displayed. Without a form that contains the fields, those fields are invisible. In this respect, a Notes form is comparable to a Claris FileMaker layout.) However, an API application can read fields regardless of what form was used to create the document.
C API applications can generally be as efficient as the client and server itself - although, since the HiTest C and Notes C++ APIs are built on top of the C API, HiTest C and Notes C++ applications have an extra layer between them and the Notes Core, and do therefore incur some performance penalty. Figure 5 shows the layering of functionality in the Notes architecture.
Figure 5. Notes architecture and the APIs
Notes C API
The API is implemented as a library of over 1000 C language functions, data structures, and symbolic constants to access Notes databases, network services, and administration services. The number of exposed functions from Notes Release 3 to Release 4 has increased by more than 50%, while maintaining compatibility with source code written for Release 3 API programs. The API is supported on every platform that supports a Notes client or Notes server.
Why use the Notes C API?
Given that both LotusScript and Agents can be used to automate the Notes client, and that a GUI interface can be built on top of a database, why should it be necessary to write a standalone Notes application in C? Notes API applications give the programmer flexibility and options that are not available in any other way.
There are many situations where it is appropriate to use the API, rather than developing internally in Notes.
You may wish to create a customized user interface for a target environment.
API programs do not require the Notes client application to be running. In contrast, to run applications using LotusScript or Notes database tools requires that the Notes client be running, which increases RAM overhead.
The task may not be achievable using only the tools available within the Notes client.
The application may need to integrate tightly with an in-house development environment other than Notes, or may need to integrate with off-the-shelf code libraries.
API capabilities
Among other things, the Notes C API can:
create, delete, and copy Notes databases
read, write, and modify Notes documents
search, sort, and index documents in Notes databases
send mail messages and documents
read, write, and modify the design of a Notes database
read, write, and evaluate formulas
perform system Administration (invoke replication, modify the ACL, log user access)
API limitations
The Notes C API cannot:
interact with the Notes user interface (e.g., it cant force Notes to open a window)
access the Notes Desktop database
run an API program if Notes is not installed
The C API toolkit
The API Toolkit includes the API header files and libraries, a large number of sample programs, and documentation. The sample programs show how to use the API functions, using a representative selection of the functions. The Toolkit documentation comes as two Notes databases, a Users Guide which introduces the concepts and functionality of the C API, and gives details on application development for each of the various supported platforms, and a Reference Guide, which explains every function, data structure, and symbolic constant used in the C API.
C API application development
C API applications for Mac OS are developed natively on a Macintosh. The official development environment is MPW using the Symantec C compilers for 68K and PowerPC. All development tools are included on the Essential Tools and Objects (ETO) CD-ROM, published by APDA. Makefiles are included for all samples, as are MPW build scripts that automate the use of the makefiles. In addition to the Symantec compilers for MPW, the Metrowerks PowerPC compiler for MPW can be used, as can the Symantec Project Manager for PowerPC and the Metrowerks IDE for PowerPC. The Mac OS development environments are discussed in detail below.
Data Types
When talking about Notes standalone programmability, it may be useful to forget that the client application even exists, and think of Notes as an API to a database engine. In this paradigm, everything is a database. Even email can be accessed via database calls.
All API data structures are logical structures, and not necessarily physical structures. Programmers should not assume that any data structures in the API correspond to actual file formats. Notes database file formats are not publicly available.
Database header
Every database has a header which contains the database title, categories, access control list, replication history, and the user activity log.
Note (Document)
A note, more commonly called a document, contains its own header followed by any number of items, which are the actual data fields or items. (The terms item and field are sometimes used interchangeably.)
Notes canonical format
All Notes internal data is stored in Intel byte ordering with no pad bytes. Generally, Notes insulates API programs from the details of conversion. For certain data types, the programmer is responsible for the conversion. The Notes C API Users Guide documents this, and the sample programs in the C API Toolkit demonstrate how and when to do the conversion. In the future, the Notes C++ API will do all the conversion automatically, and byte ordering and alignment will cease to be an issue.
Each Notes server can support one or more databases. Each database can contain one or more documents. Each document can contain one or more items. Each item has a distinct data type. Data types fall into two categories: simple and composite.
Simple data types
Simple data types include:
Text and Text List: e.g., subject field of a mail memo
Number and Number List: e.g., part number or order number
Time/Date and Time/Date Range or List: e.g., date field
Composite data types
Composite data types include:
Rich Text. The functionality provided by Lotus Notes Rich Text is actually a superset of the industry standard (Microsoft RTF). However, the data structures used in Lotus Rich Text are different than those used in Microsoft Rich Text. The C API Toolkit contains sample programs and source code to create and manipulate Rich Text, and to call the import and export libraries to convert between Microsoft Rich Text and Lotus Notes Rich Text. Lotus Notes Rich Text may contain bitmaps and hyperlinks (also called doclinks) to other documents.
Object: e.g., embedded OLE object, file attachment
Tables: e.g., tabulated data, spreadsheet-like grid
User Data: Programmers can define their own data types which are not interpreted by Notes, but are simply stored as a stream of binary data.
Searching a Database
Using the C API, there are four ways to search a Notes database.
Linear: Scans all documents in a database, applying search criteria. This type of search should be used when the search criteria are not known until runtime. The linear search is accomplished using a C API function that takes as an argument a pointer to a function that the programmer defines, called an action routine. The action routine is called for each document that matches the search criteria. Linear is an inefficient search method.
Indexed: Uses views to sort and categorize documents. This type of search should be used when the order of matched items is important. At runtime the programmer may create the view to specify the hierarchy.
Full Text: To be used if search keywords might be in Rich Text fields.
Direct Access: Not a search, but if the Note ID of the document or the name of an item within a document is known, it can be accessed directly. In other words, if the programmer knows where the data is, the programmer is not forced to use the search API in order to access it.
Notes Security
Users want to know that their workstations are secure, and IS departments want to know that their servers and networks are secure. With all the talk about the Internet and its being perceived as having low security, developers can take advantage of the fact that Notes is secure.
Notes provides user identification, access control lists, and password protection as well as encryption. It is important to know how this affects API applications, in order to take advantage of the features of Notes security.
User ID (Notes ID)
Every user is assigned a User ID, sometimes called a Notes ID (not to be confused with a Note ID; a User/Notes ID identifies a person, while a Note ID identifies a document or note). A User ID contains the users name, a Notes license number, a certificate which enables access to servers which are set up to recognize that certifier, and both a public and private encryption key. To access databases, a user would need a User ID file plus a password. This is far more secure than merely typing a username and a password, since a User ID can only be transmitted electronically (or physically). Notes Release 4 adds an additional level of security over Release 3 by offering encryption on the workstation. An API program can use only one User ID at a time.
Access control lists (ACL)
An Access Control List is a list of users, specifying what level of access each user has to a database. Each entry in the ACL contains a user name, access level, flags, and roles. Every database must contain an ACL.
Server-level security
The user of an API program must have access to the server. An API program cannot open a database that the user could not have opened through the Notes user interface.
Database-level security
Database-level security is controlled by the ACL, which defines who can use a database and what operations they are permitted there.
View-level security
If the view has a read access list, then it is enforced in the API. If the user does not have access to the view, the error message will indicate that the view does not exist.
Form-level security
If a form has a read access list, then it is enforced in the API if the API program implements it. The API ignores the compose access list for forms.
Document-level security
The document read, editor, and author access control lists are enforced by the API. For example, if the user does not have read access to a document, NSFNoteOpen() will fail, and NSFSearch() will not find the document. If a user has read access but not author access, then NSFNoteOpen() will succeed, but NSFNoteUpdate() will fail and will return the error ERR_NOT_AUTHOR.
Section-level security
A form may contain one or more sections. A section is a field that contains a list specifying who can edit the fields that follow the section field. Sections are not a real security feature, though, and an API program can write to or append to any field in a document regardless of section information.
Field-level security
Fields may be encrypted, and it is the responsibility of the API application to decrypt the field.
Encryption
Every Notes user is automatically assigned public and private encryption keys. The public key is usually stored on the Notes server. The private key is usually stored on the users hard disk. A personal key is just another name for the private key; the personal key is used when a user wants to encrypt a document that will be kept locally.
The public and private keys are used for sending encrypted email. Notes hides the complexity of this from the user, who merely clicks a checkbox to enable encryption. Email is encrypted using the senders private key and the recipients public key. When the recipient receives the email, it is decrypted using the senders public key and the recipients private key.
Notes supports attaching a signature to an email, which also makes use of public and private keys.
Domestic vs. international
Notes uses RSA encryption, which has been classified by the US Government as a military technology, and thus the North American version of Notes cannot be exported in its most secure form. To send an encrypted email or document outside of the US or Canada, the International English version of Notes must be used, which has a slightly less but still quite secure level of encryption.
Field-level encryption
Documents are not encrypted; fields are. It is best to think of the document as a collection of items, all of which have been set up as encryption items. For example, the body field of an email is encrypted, but the to and cc fields are not.
Notes C++ API
The C++ API is not yet released, but will soon be available as a general beta release. It is built on top of the C API, and provides true OOP, with all the benefits of C++. One implementation goal of Notes C++ was to minimize the performance overhead. Notes C++ is single-chain, not multiple-inheritance.
Developer benefits
These include:
Reduced application code size. Much of the code that the C API leaves to the individual developer is handled by the C++ classes in its high-level functions and data abstractions.
Reduced application debugging and maintenance time, as well as more readable code. Since it is C++, there is type-checking done at compile time. The C++ classes implement run-time exception handling that is supported via catch and throw. In addition, failable functions return status codes, which may be used both as information and to indicate an error.
Sophisticated memory management. If an object allocates memory, it is responsible for freeing it. If the programmer allocates memory, the programmer is responsible for freeing it. If the programmer allocates an object but forgets to free it, it is automatically freed when the object goes out of scope.
Ease of learning. The C++ classes are easier to learn than the hundreds of C API functions or the HiTest C objects.
Rapid development and deployment.
Multi-platform support. The API will support every platform that the Notes C API supports.
Searching a database
The C++ API has all of the searching capabilities of the C API, plus more. The C++ API-specific navigation includes:
// Iterators (class maintains the state)
ACLEntry = ACLEntryIterator.GetNextEntry();
// Arrays (indexed access to data)
Doc = Documents[i];
// Named data can be directly accessed
Status = Database.GetForm("Discussion Topic", &Form);
Vendor-Independent Messaging
The Vendor-Independent Messaging (VIM) Interface began as an industry-standard, platform-independent application programming interface specification for messaging systems. It has evolved into the Lotus email standard interface for Notes and ccMail. In addition, various Lotus products have different levels of support for such interfaces as MAPI (Messaging Application Programming Interface), CMC (Common Mail Call), and SMI (Simple Messaging Interface). In future releases, Notes will support POP (Post Office Protocol) and SMTP (Simple Mail Transfer Protocol), but it would be very premature to discuss the level of support for these protocols that will be available through the API.
The VIM API enables programmers to write applications that link the functionality of messaging systems to the functions provided by end-user applications. With VIM, the resulting mail-enabled or mail-aware applications can be developed over a wide range of platforms. VIM provides a single interface that allows programmers to combine the services of various messaging systems into one application. Using the VIM API functions, one can design a number of specialized mail-enabled applications. For example, a programmer could develop an application designed to analyze real-time stock prices and send an email when a particular stock reaches or drops to a certain price.
The Lotus VIM Developers Toolkit provides header files, libraries, documentation, and sample programs, and is compatible with Notes-based electronic mail.
VIM does a few things that cannot be done using the C API, and does many things in a manner that is more convenient for the programmer. The C++ API will have a class implementing basic email capabilities; however, keep in mind that the C++ API is built on top of the C API, not VIM.
Some of the most important features of VIM include its ability to:
compose and send messages with file attachments
receive, store, and process delivered messages
search and modify address books
interoperate with ccMail
Leveraging Apple Technologies
Newton
The Notes C API Toolkit currently contains one Newton sample called MakeBook, and will soon have more. The sample program exports the Notes C API Users Guide database into a form that can be transferred to the Newton and be read by the built-in Newton Book browser. This requires the use of an Apple-supplied Newton Book compiler called Book Maker, plus the Newton Developer Toolkit to build the output of Book Maker into a package and to download that package to the Newton. This program was demonstrated at the LotusSphere 96 conference in Orlando. Browsing the Notes C API Users Guide on the Newton is actually faster than browsing it using Notes Release 4 on a PowerPC or a Pentium-based machine, even if the database is stored locally on that machine. (Let us, however, keep this in context. MakeBook, though it could be modified to export any Notes database, is not a general-purpose Notes database export tool for end users, but rather a technology demonstration.)
DILs
Apple has recently released the Newton Desktop Integration Libraries (DILs) to enable developers to write Mac OS and Windows applications that exchange data with the Newton. In the future, the Notes API group may be releasing sample programs that show how to leverage the DILs in Newton/Notes applications. Recall that the MakeBook sample uses another program to transfer the data to the Newton from the Mac or Windows machine; functions in the DILs might handle that task.
OpenDoc
OpenDoc has the potential to be a key Notes development tool, since OpenDocs concept of containers and parts is somewhat analogous to the Notes paradigm of the Notes client application and runtime services implemented by databases, LotusScript, and API programs. The Notes API group is looking at ways to integrate the Notes API into OpenDoc to provide sample OpenDoc parts in the Lotus Notes C API Toolkit. Nothing has been planned at this time, but keep in mind that the Windows and OS/2 versions of OpenDoc are being developed by IBM, which recently acquired Lotus.
AppleScript
AppleScript can be used to make an application programmable by end users, and can be used to implement programmability between applications. Although the Notes client application is not AppleScript-aware, it is possible to create an AppleScript-aware application that provides an interface between AppleScript and the Notes C API. (This is very different from scripting the Notes client, a task that should be done using LotusScript.) For example, imagine implementing the AppleScript database suite, or some variation of it, which uses Notes as its database, as implemented via the C API. Another idea would be to use AppleScript to implement a layer on top of VIM, to make it easier for developers to mail-enable their applications. Lotus is also working on a glue layer interface between LotusScript and AppleScript.
Mac OS Development Environment
Shared library technology
The C API is implemented as a shared library on Mac OS (as on UNIX; it is implemented as a number of DLLs on Windows and OS/2). Although the library is linked with the application, the actual code does not get copied into the application. If more than one application uses the same shared library, only one copy needs to reside on the users machine. Both Notes and the API application call into the same copy of the shared library code. In addition to saving disk space, using shared libraries for Lotus Notes ensures that both Notes and API applications will always be running with the same version of the libraries.
For a long time, Apple did not provide a shared library technology for developers to use. This is the main reason why Notes Release 3 did not have a developer-accessible API. Then Apple implemented the Apple Shared Library Manager (ASLM) for 68K Macintosh models only, followed by the Code Fragment Manager (CFM) for PowerPC Macintosh models only. Thus, when the Notes Release 4 project began, there was no choice but to implement the 68K version with ASLM and the PowerPC version with CFM.
Today, both ASLM and CFM are available on both platforms, but too late for Notes Release 4. While this has no impact on Notes users or on Notes API code, it does have an impact on what linkers can be used to develop a Notes API application. Restriction of linker choices restricts compiler choices, and development environment choices.
MPW support
The current release of the API Toolkit for Mac OS recommends the use of MPW with the Symantec compilers for 68K and PowerPC. It is possible to use the Metrowerks compiler for PowerPC, but not the Metrowerks compiler for 68K, since Metrowerks does not support linking ASLM shared libraries. It is not possible to use Metrowerks to build 68K Notes API applications.
The C API Toolkit includes an MPW UserStartup file and a number of script files and makefiles, to ease development of the sample applications, and to provide a foundation for developing new projects. The C API Users Guide that is included with the Toolkit provides extensive documentation on setting up the development environments for each platform that the Notes API supports.
Symantec and Metrowerks project environment support
Notes C API PowerPC applications can be built using the Symantec Project Manager. Notes C API PowerPC and 68K applications can be built using the Metrowerks IDE. Unfortunately, using Symantec Think C for building 68K Notes API applications is extremely difficult, and is not something that is being looked into further at this time.
Information on using the Symantec Project Manager and Metrowerks IDE for Notes C API development can be found at http://www.Lotus.com/devtools/21da.htm, as well as in the documentation that is included with the C API Toolkit.
Support of the Symantec and Metrowerks Project environments for the Notes C++ API Toolkit is a goal, since this will enable developers to use the class browsers, as well as easing the integration with the Symantec and Metrowerks class libraries.
Code Sample
Disclaimer: All of the header files, some macro definitions, and lots of error checking have been removed in an effort to make this code simpler, shorter, and easier to read. The full (and working) source code for this program is included on the Notes C API Toolkit CD-ROM, along with makefiles and build instructions for Mac OS 68K and PowerPC, and Windows 16- and 32-bit.
Listing 1: MakeBook.c
Globals
FILE *outfile = NULL;
long uniqueLabelCounter = 0;
char *field_text;
Main
This standalone program is declared with argc and argv, even though these arguments cannot be used in
the Mac OS, unless it were to be built as an MPW tool. Aside from the conditional code for initializing the
Mac OS toolbox, all of this source is 100% platform independent. (The actual sample code on the Notes
C API Toolkit CD ROM contains a macro that hides platform specific initialization.)
All output from this program goes to a text file, which is created and written using the standard C file i/o routines.
Again, this choice of file i/o was made for platform independence. In Notes API applications, one may choose
to use conditionally compiled code to add platform specific file system functionality such as Mac OS file
types.
NotesInitExtended() is a Notes API function that initializes the Notes runtime library. At the end of main(),
NotesTerm() is called. Every standalone program must have one set of init and term calls. Multi-threaded
applications must have one set of calls for each thread. In this program, NotesTerm() is called as part of
the macro API_RETURN().
The database is opened using NSFDbOpen(), processed with the function ReadDatabase(), and then closed
using NSFDbClose(). The open function returns a handle to the database, which is then used by all functions
that refer to that database. NSFDbOpen() takes the name of database as a full pathname, or as a filename
if that database is stored locally. If the database is stored on a Notes server, there is an API function that
will build the pathname.
void main(int argc, char *argv[])
{
DBHANDLE db_handle; // handle of source database
STATUS error = NOERROR; // return status from API calls
#ifdef MAC
InitMacToolBox();
#endif
if ((outfile = fopen("book.src", "w")) != NULL)
{
//
// Output data that is required by the Apple Book Maker application, for the
// creation of a Newton Book.
//
// For more information, please refer to the Newton Book Maker Users Guide,
// which is included with the Apples Newton Toolkit for Mac OS and Windows.
//
fprintf(outfile,
"\
.isbn Notes:LOTUS\n\
.date 02/05/96\n\
.author Rick Gansler\n\
.publisher Lotus Development Corp.\n\
.copyright (c) 1996 Lotus Development Corp.\n\
.shorttitle API User\n\
.title Lotus Notes - API Users Guide\n\
.blurb\n\
The Lotus Notes API User's Guide exported from Notes to
Newton Book format.\n\
.layout Indented 1 Sidebar 11\n\
.layout TitlePage 12 NoTitle\n\
.layout ContentsPage 2 Sidebar 10 Main NoTitle\n\
.layout Default 12\n\
");
// Initialize the Notes runtime library
if (NotesInitExtended(argc, argv))
NOTES_INIT_ERROR;
// Open the database
if (error = NSFDbOpen("API40UG.NSF", &db_handle))
API_RETURN(ERR(error));
field_text = (void *)malloc(32000);
// Generate the Newton Book contents
uniqueLabelCounter = 0;
error = ReadDatabase(db_handle);
if (error)
{
NSFDbClose(db_handle));
API_RETURN(ERR(error));
}
// Close the database
if (error = NSFDbClose(db_handle))
API_RETURN(ERR(error));
fclose(outfile);
free(field_text);
}
API_RETURN(NOERROR);
}
ReadDatabase
ReadDatabase() takes a database handle, and reads each document in the database. In this case, the database
has a view that is defined in the database. One could also create a custom view at runtime. The pairing of
a view and a collection is analogous to a search result that has been sorted. Once the collection has been
opened, ReadEntries() is called to return a buffer containing a reference to each document in the collection,
plus a counter that indicates how many documents are in the collection. Each document is identified by its
unique note id. A loop is used to iterate through the buffer and pull out each note id, which is passed to the
function ReadNote().
STATUS ReadDatabase(DBHANDLE db_handle)
{
STATUS error=NOERROR; // return status from API calls
NOTEID ViewID; // note id of the view
HCOLLECTIONh Collection;// collection handle
COLLECTIONPOSITION CollPosition; // index into collection
HANDLE hBuffer; // handle to buffer of info
DWORD EntriesFound;// number of entries found
WORD SignalFlag;// signal and share warning flags
BYTE *pBuffer;// pointer into info buffer
DWORD I;// a counter
NOTEID EntryID; // a collection entry id
// Get the note id of the view we want
if (error =
NIFFindView(db_handle,"TABLE OF CONTENTS",&ViewID))
return(error);
// Get the current collection using this view
if (error = NIFOpenCollection(
db_handle,// handle of db with view
db_handle,// handle of db with data
ViewID, // note id of the view
0, // collection open flags
NULLHANDLE, // handle to unread ID list (input & return)
&hCollection, // collection handle (return)
NULLHANDLE, // handle to open view note (return)
NULL, // universal note id of view (return)
NULLHANDLE, // handle to collapsed list (return)
NULLHANDLE)) // handle to selected list (return)
return(error);
// Set a COLLECTIONPOSITION to the beginning of the collection
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 0;
// Get the note ID and summary of every entry in the collection. In the
// returned buffer, first comes all of the info about the first entry, then
// all of the info about the 2nd entry, etc. For each entry, the info is
// arranged in the order of the bits in the READ_MASKs.
do
{
if (error = NIFReadEntries(
hCollection, // handle to this collection
&CollPosition, // where to start in collection
NAVIGATE_NEXT, // order to use when skipping
1L, // number to skip
NAVIGATE_NEXT, // order to use when reading
0xFFFFFFFF,// max number to read
READ_MASK_NOTEID, // info we want
&hBuffer,// handle to info buffer (return)
NULL, // length of info buffer (return)
NULL, // entries skipped (return)
&EntriesFound, // entries read (return)
&SignalFlag)) // share warning & more signal flag return
{
NIFCloseCollection(hCollection);
return(error);
}
// Check to make sure there was a buffer of information returned
if (hBuffer == NULLHANDLE)
{
NIFCloseCollection(hCollection);
NSFDbClose(db_handle);
return(NOERROR);
}
//
// Lock down (freeze the location) of the information buffer. Cast
// the resulting pointer to the type we need.
//
// OSLockObject() is sort of like the Notes equivalent of locking a
// Mac handle and then dereferencing it. However, Notes abstracts
// memory management, since each Notes platform may implement it
// differently. For example, a Windows handle is a very different kind
// of data object than a Mac handle.
//
pBuffer = (BYTE *) OSLockObject (hBuffer);
// Start a loop that extracts the info about each collection entry from
// the information buffer
for (i = 1; i <= EntriesFound; i++)
{
// Get the NoteID of this entry
EntryID = *(NOTEID*)pBuffer;
// Advance the pointer over the NoteID
pBuffer += sizeof(NOTEID);
if (! (NOTEID_CATEGORY & EntryID))
ReadNote(EntryID, db_handle);
}
// Unlock the list of NoteIDs.
OSUnlockObject(hBuffer);
// Free the memory allocated by NIFReadEntries
OSMemFree(hBuffer);
} while (SignalFlag & SIGNAL_MORE_TO_DO);
// Close the collection
error = NIFCloseCollection(hCollection);
return(error);
}
ReadNote
ReadNote() takes a note id and a database handle, opens the document referred to by the note id, reads
only the fields in that document that are needed, formats them, and outputs them to a text file in a form that
can be imported by the Apple program Book Maker.
STATUS far PASCAL ReadNote(NOTEID noteID, DBHANDLE db_handle)
{
NOTEHANDLE note_hdl;
WORD field_len;
long sectionNum_num;
long chapterNum_num;
char sectionName_text[100];
char titleName_text[100];
STATUS error;
static longprevSectionNumber = -1;// this is a static
// Open the document whose note id was passed to this function
if (error = NSFNoteOpen(db_handle,noteID, 0, ¬e_hdl))
return(ERR(error));
sectionNum_num = NSFItemGetLong(note_hdl, "SectionNumber", 0L);
chapterNum_num = NSFItemGetLong(note_hdl, "Chapter", 0L);
field_len = NSFItemGetText(note_hdl, "SectionName",
sectionName_text,
sizeof (sectionName_text));
field_len =
NSFItemGetText(note_hdl, "title", titleName_text,
sizeof(titleName_text));
// If this document is the first in a new chapter, create a new heading in the
// Newton Book Overview (or table of contents)
if (sectionNum_num > prevSectionNumber)
{
prevSectionNumber = sectionNum_num;
fprintf(outfile,
".subject 1 startspage centered name=%ld\n",
(long)uniqueLabelCounter++);
fprintf(outfile,
"(%ld) %s\n",sectionNum_num,sectionName_text);
}
// Every document gets an entry in the Newton Book Overview.
fprintf(outfile,
".subject 2 name=%ld\n", uniqueLabelCounter++);
fprintf(outfile,
"(%ld) %s\n", chapterNum_num, titleName_text);
// Body of the document (Notes Rich Text field)
if (NSFItemConvertToText(note_hdl, "text", field_text,
FILE_SIZE, \0) > 0)
{
// If the data from Notes contains a \r\n, then remove the \r.
// The code for this function is not included in this listing.
ProcessLineFeeds(field_text);
// If the data from Notes had a line that began with a period, that would
// confuse Book Maker, so we replace the period with a space.
// All Book Maker commands begin with a period at the start of a line.
// The code for this function is not included in this listing.
CorrectLinesStartingWithPeriod(field_text);
fprintf(outfile, "%s\n", field_text);
}
// Close the note
if (error = NSFNoteClose(note_hdl))
return(ERR(error));
return (NOERROR);
}
Summary
Lotus Notes Release 4 presents the Macintosh community with a very exciting opportunity. First, Release 4 is a complete overhaul of the user interface and functionality of Release 3, so should be well received by Mac users. Second, Release 4 exists in both 68K and PowerPC-native versions. Lastly, current support for LotusScript and the C API, and future support for VIM and the C++ API, give Macintosh developers the tools to bring custom Notes-based solutions to the Macintosh platform, as well as to take advantage of Apple technologies by incorporating them into custom Notes applications.