Lotus Notes FAQ Visit Our Sponsor!


Lotus Notes Frequently Asked Questions
(Notes 4.x)

A. Administration Tips


1. How do you update a Stored Form in old documents?
2. How do you get rid of inactive sessions on a server?
3. How do you convert Word files to Notes format?
4. How do you fix the server name resolution problem with Netware NDS?
5. Can Notes be attacked by Viruses?
6. How do you set the outgoing domain name in the SMTP MTA on a per user basis?
7. Why aren't laptop user's database designs being updated?
8. How do I set up searching for numbers and punctuation with FT Search?
9. Is Notes Year 2000 Ready?
10. Why can't I access a database design although I have Designer Access?
11. What keyboard shortcuts are available in Notes?
12. What do you do about forgotten passwords?
13. Why isn't my @DbLookup background macro running properly?
14. How do you run the Compact process on a schedule?
15. Can you support multiple SMTP domains using the SMTP MTA?
16. How do you warn users that a server will be shut down?
17. How do you check the difference between two documents?
18. How do you fix documents with bad ReaderNames fields?
19. How do you specify a new location for the desktop.dsk file?
20. How do you add a disclaimer/signature to all outgoing SMTP mail?
21. What can the Lotus SMTP MTA do to prevent SPAM?
22. What Virus scanning packages are available for Notes?
23. What is configurable in the Lotus SMTP MTA?
24. How do you remove Stored Forms from documents?
25. Why do users get notified of new mail even though they don't have any?
26. What would change the list of servers I see in the Database Open dialog?
27. What TCP/IP port does Notes use?
28. How do you run Notes in "Kiosk" mode?
29. How do you make backup copies of created user ID's?
30. What can be done to optimize database performance?
31. Why can't users with Depositor access create documents even though I have enabled Public Access on the form?
32. How do you make a list of all groups a person is in?
33. Why do new documents not show up in views after a recent server crash?
34. How do you turn off Notes crash dumps (notes.rip files)?
35. Can you use the SMTP MTA over a dial-up link?
36. Can I set the default ACL on the N&A Book to Reader?
37. Can you keep multiple versions of Notes on the same system?
38. What programs will back up Notes databases without needing a Notes server shutdown?
39. How do you change the mail file design to use the Notes 4.5 mail template?
40. How do you minimize Notes rollout cost?
41. How do you upgrade the max size of a database?
42. Can you open a database automatically when Notes starts?
43. How do you get Notes to rebuild corrupted views?
44. Who can I call to find my local reseller and licensing information?
45. Can you check for mail without leaving Notes running?
46. How do you fix the Mail Archiving Agent so it keeps documents in the right folders?
47. How do you manage ACL information across an organization?
48. Can fields be added to the N&A Book?
49. How do you make the infobox reappear if it doesn't show up?
50. How do you change the available letterheads in mail?
51. How do you change the Lotus SMTP MTA space replacement character to '.'?
52. How do you put a Notes Database on a CD?
53. What is involved in deploying Notes to International users?
54. How do you create a database that is usable as an address book for name lookup?
55. How do you move databases onto a different drive without the user knowing about it?
[<a href="#NT00000FC2">56. How can I use a POP3 client, such as Netscape or Eudora, to
access my mailbox in Notes?
</a>]
57. How do you prevent groups from being expanded when sending mail?
58. How do I get rid of the encap2.ond attachment on outgoing Internet mail?
59. How do you shut the server down for backups?
60. What Netware address does a Notes server use?
61. Can you synchronize unread marks if a user has multiple machines running the Notes client?
62. How do I add additional N&A books to the address lookup dialog?
63. How do you change the password on the Certifier ID?
64. Are there any large-scale deployment guidelines?
65. How do you update the SmartIcons on all your users' workstations via LotusScript?
66. How do you add Quoted Reply support to Notes' mail templates?
67. How can you have multiple users on one workstation?
68. Can you have specific notes.ini files per user?
69. How do you change how long logs are kept in log.nsf?
70. How do you transfer data between Notes and other databases?
71. How do you set up remote users with a local replica of a new database?
72. How do you refresh Private View designs on clients?
73. Why does my mail say it is sent from someone else?

B. Books and Magazines


1. IBM Redbooks
2. Helpful Non-Notes Books
3. Books for Notes 4.x
4. Lotus Notes Magazines

C. Domino


1. Can you force a user to log in before using a database?
2. How do you replace the "No Documents Found" message in an empty view?
3. Does Domino support Hierarchical Names?
4. Is it possible to run a Domino server on a stand-alone PC?

5. How do you add a button that clears the fields in the form?
6. What URL do you use to create a new document in a database?
7. How do you reopen a saved new document in read mode?
8. How do you use a different column as the hotspot to a document in a view?
9. Can you prevent the browser from prompting for a password when you use multiple web servers for your site?
10. How do you make parts of a document visible only to Web users or Notes users?
11. Can Domino use directory links to reach databases?
12. How do I refresh a page without losing information already entered?
13. How do you add Java applets which have multiple class files?
14. How do you display the number of search results on a page?
15. How do you reference view names with "/" and "\" in them?
16. How do you remove the Domino footer from beta versions of Domino?
17. Can you put the action buttons for a view in a different frame?
18. Can you do a Query by Form?
19. Can you set Notes fields from JavaScript?
20. How do you use a URL to reference a specific document in a view?
21. How do you use transparent GIFs for web navigators?
22. How do you pass parameters to OpenAgent?
23. Can you have Domino search a specific view instead of a database?
24. How do you target a frame panel from a Navigator?
25. How do you delete the current document?
26. Can you target a frame using @URLOpen?
27. How do you validate and jump to fields which have validation errors?
28. How do you prevent people from deleting file attachments?
29. How do you remove the Domino-generated Navigation Bar from Views?
30. Can you store transparent and animated GIF's in the Notes database for a site?
31. How do you work around Domino's keyword field deficiencies?
32. How do you decode parameters in URLs?
33. Can you create field help on a web browser?
34. How do you put HTML code before the tag?
35. How do you improve performance to web clients?
36. How do you remove Domino's default submit button?
37. Can you display a text field as a TEXTAREA?
38. How do you prevent web users from being able to browse your database directory?
39. Can you do banner ads with Domino?
40. How do you detach a file submitted by a web browser?
41. How do you make user registration immediate?
42. How do you refer to CGI variables in a $$Query*Agent?
43. How do you delete a document by the UNID?
44. How do you set up a field to autowrap when text is typed in a browser?
45. How would you secure a Domino server?
46. How do you prevent people from submitting a form multiple times?
47. How do you add a Javascript button which validates the form and then submits it?
48. How do you give a Value= tag to a field?
49. How do you set a Cookie?
50. How do you make a field look like a password field?
51. When do you have to pay for Client Access Licenses (CALs)?
52. What @Command do you use to delete the current document?
53. Can you automatically expand sections in documents?
54. Can you change the Twistie graphics in Notes Views?
55. Are @PostedCommands Supported?
56. Can you put a background bitmap in the About document?
57. How do you access fields on a Parent document from an unsaved response doc?
58. Why do you need Author access to do a search on a database?
59. Can you make a link that lets the user jump back two web pages?
60. Can Domino forms be mail-enabled?
61. Can you have a single URL that opens the user's mailbox?
62. How do you pass variables into a form via URL's?
63. Why do I get SSL errors when using MSIE?
64. Can you change the look of the search input form?
65. Can you have multiple navigators on one page?
66. Can views be shown to web clients with the Notes V4 UI?
67. Can you get rid of Domino's tags?
68. How do you make a Domino site searchable by web search engines
69. How do you add context-sensitive help on Domino web pages?
70. What companies will host Domino web applications for a fee?
71. How do you open the About This Database document with a URL?
72. How do you select multiple documents in a view and run an action button on them?
73. How do you jump back to the current view from the current document?
74. How do you handle field inheritance when composing from the Web?
75. Can you customize the "Deleted" message?
76. Does Domino support Server-Side Includes (SSI)?
77. Can you attach files to a document using a web browser?
78. How do you create a framed page with a navigator in one frame?

D. Education and Training


1. Flash Cards
2. Computer Based Training
3. Virtual Classes via the Internet
4. Lotus Education Helpline

E. FTP Archives


1. Notes Utilities
2. Notes Related Programs or Information

F. Internet Gateways


1. How do I publish Notes databases as Web pages?
2. Where can I get a Web browser gateway for Notes?
3. Can Notes be used as a POP3 Client or Server?

4. Where can I get a Usenet News(NNTP) gateway?

G. Mail Gateways


1. OfficeVision and SNADS
2. Trusted MIME
3. PalmPilot
4. FAX
5. POP3
6. Migration Tools
7. MS Exchange <-> Lotus Notes
8. NetTalk (X.500, LDAP, IMAP, Exchange, cc:Mail)
9. Windows CE

H. Mailing Lists


1. DOMJOBS
2. LNotes-L
3. DominoLinux
4. Oklahoma State Notes-L
5. NotesMac
6. Oklahoma State Domino-L
7. NotesMTA-L
8. Domino-L

I. Notes Platforms


1. How do you start Notes automatically on bootup in Solaris?
2. How do you set up a Digiboard under OS/2?
3. How do you change the new mail sound on a Mac?
4. How do you set up server proxying through MS Proxy Server?
5. Which file system should be used for the Notes server?
6. How do you set up IWP forms input when running Microsoft IIS as the web server?
7. How do you tune the operating system for running Notes?
8. Which platform is best for a Notes server?
9. How do you get NT to reboot automatically after the Blue Screen Of Death?
10. How do you generate a core dump for IBM to look at?
11. Where can I find info on Mac-specific (not Notes-related) problems?
12. How do I install Notes as an NT Service?
13. How do you get the Notes server to run in the background?
14. Why can't Notes clients see my new Notes server running IPX?
15. How do you set up NetBIOS?
16. How do you change the new mail tune under NT?
17. How do you determine the NT Service Pack Level using LotusScript?
18. How do you back up the server automatically?
19. How do you set up the modem port for Solaris 2.x?
20. How do you run the Notes server in the background but still be able to control the console?

J. Programming Tips


1. Why don't bitmaps display properly on some systems?
2. How do you write DbLookups so they work on a local database and on the server?
3. How do you display a button next to a field only when editing?
4. How do you restrict a field to contain alphanumeric characters only?
5. How do you validate that a field has alpha characters only?
6. How do you total a column at the bottom of a view?
7. Can you have views based on the current user name?
8. How do you categorize and count the number of documents created in a particular week?
9. How do you reduce database size by deleting unused fields?
10. From a response document, how do you update a field in the parent document?
11. Can LotusScript operate on Private Views?
12. Can you have an agent send mail as a specific person?
13. How do you get the directory the current database is in?
14. How do you automatically copy an ACL from a template into a new database?
15. How do you display a number field with leading zeroes?
16. How do you add more action buttons than fit on the display?
17. How do you prevent a form from prompting to save it?
18. How do you automatically filter mail in Notes?
19. How do you create a view action button that creates responses to only work on main documents?
20. How can you tell if a field has been changed in LotusScript?
21. Can you inherit fields from parts of the same form?
22. How do you do a mail merge using info from existing documents?
23. How do you generate sequential document IDs?
24. Can you show FTSearch documents with a specific view?
25. How do you make a view to use for checking for replication conflicts?
26. Can you access the Clipboard in Notes?
27. How do you save a document, then create a new document in its window?
28. How do you force the value of a field to be unique?
29. How do you find the positions of a string in a text list?
30. How do I get the week ending date for a specific day?
31. Why does @Explode only give me the first item?
32. How do you delete Environment variables from the notes.ini file?
33. How do you prevent people from viewing with a different form and saving the result?
34. Can you use @UserName in a view?
35. How do you sum number fields which have not been edited and initialized?
36. Can you work around some of the size limitations in LotusScript programs?
37. How do you synchronize fields between documents created with two different forms?
38. How do you automatically format phone numbers?
39. How do you select only Response documents in a view?
40. How do you validate a credit card number?
41. Can you make a popup calendar in Notes?
42. How do you get the current access level of a user?
43. Can you open a view in full screen mode from a Navigator?
44. How do you generate a subset of list values based on the contents of another list?
45. How do you keep a running history of all entries in an RTF field?

46. Can you use @Functions in LotusScript?
47. Can you use views from the Mail template in your own databases?
48. How do you compare date/time fields using Lotuscript?
49. How do you go to the last document in a category using Lotuscript?
50. How do you create mailing labels in Notes?
51. What are the Unix syntaxes for calling DLLs from LotusScript?
52. Can you dynamically select documents per user without using a ReaderNames field?
53. How do you display documents created with a form using a layout region?
54. Why doesn't NotesUIDocument.GetFieldText return the alias for a keyword selection?
55. Why doesn't my "If documents have been created or modified" agent execute immediately?
56. How do you insert a new line in a Rich Text field using a macro?
57. How do you set the server to run agents on with a hidden database design?
58. How do you sort a document collection?
59. What HelpDesk products are available for Notes?
60. How do you force a user to use a button to save a form?
61. Can you start a program in Notes and wait for it to finish?
62. How do you access a specific element of a multi-value field?
63. How do you find out what Roles a user has in the current database?
64. How do your control an OLE-VBA object in LotusScript?
65. How do you add a response's doclink to a parent document?
66. How do you track who changed a critical field?
67. How do you find the exact version number of Notes?
68. Where can I get more information on Java access to Notes?
69. How do you put a popup calendar in a layout region?
70. How do you operate on the currently selected documents in LotusScript?
71. In what order do @Commands execute?
72. How do you display progress to the user via LotusScript?
73. How do you convert a numerical value to the equivalent written text?
74. How do you open a document in edit mode if it exists?
75. How do I remove erased fields that keep appearing in the Add Fields window?
76. How do you retrieve a column total for a category?
77. How do you sort and categorize a view based on months in chronological order?
78. How do you open a Win32 File Dialog in LotusScript?
79. Can you dynamically change the color of the form?
80. Can you open a Navigator using Lotuscript?
81. How do you do @Explode in LotusScript?
82. Can you launch a URL without using InterNotes?
83. How do you get the date for Easter of a given year?
84. How do you hide the design of a database, but let the user see field names?
85. Can you access Win32 registry keys in LotusScript?
86. How do you launch an embedded object using LotusScript?
87. How do you debug into the QueryModeChange and QuerySave events in LotusScript?
88. How do I refresh a document's fields after one field is changed?
89. How do you change the title of a dialog box?
90. How do you remove an element from a Textlist field?
91. How do you avoid error messages with DBLookup?
92. How do you find the elements which are unique to a list?
93. Why don't my changes to a Rich Text field show up immediately?
94. How do signatures and sections in a form work?
95. What does the @Db NoCache parameter do?
96. How do you generate unique document numbers?

97. What happened to Tools\RefreshFields that was in Notes 3.x?
98. How do you do a data import/merge using Lotuscript?
99. How do you lock a document that is being edited?
100. How can I see if the directory exists using LotusScript?
101. How can you tell if a view is Private?
102. How do you check if an RTF field is empty?
103. How do you log off a Notes user so you can force user revalidation?
104. How do you calculate the week number in a year of a given date?
105. How do you create response documents from a navigator hotspot?
106. How do you provide context-sensitive help for your database?
107. Can you get a filename from the user in Lotuscript?
108. How do you make a Computed For Display Rich Text Field?
109. How do you look up all the people in a Group?
110. How do you make dynamically sized tables?
111. How do you send mail based on whether a field is modified?
112. How do you execute DOS commands from a formula?
113. How do I calculate the number of weekdays between two date fields?
114. Can I look up Multiple Keywords using @Db functions?
115. How do you prevent LotusScript errors when handling deletion stubs in document collections?
116. How do you monitor your own threads in a discussion database?
117. How do you notify users when documents are modified or added to a database?
118. How do you force the user to click an Edit action button to edit a document?
119. How do you copy all parts of a script from one form to another?
120. Can I lookup Rich Text using @Db functions?
121. How do you change fields based on the state of a separate keyword field?
122. How do you keep doc.send() from crashing a background agent?
123. How do you notify the author of a document when a response has been composed?
[<a href="#NT00001052">124. How do I make the "loser" of a replication/save conflict be the
"winner"?
</a>]
125. How can I control whether the @Db Function returns a list?
126. What causes the LotusScript error "Notes Error: Special Database object cannot be located."?
127. How do you return custom data types in LotusScript?
128. Can you create Shared Actions?
129. Can you use regular expressions for string matching?
130. Can you run an Agent from LotusScript?
131. How do you create Names, Readers, Authors fields in LotusScript?
132. Can you implement exclusive locking across replicated databases?
133. How do you add an Internet-style signature at the bottom of your mail messages?
134. How do you do @MailSend in Lotuscript?
135. Can you dynamically hide/unhide sections of a form?
136. How do you update a field in response documents after it is changed in the parent document?

K. Web Sites


1. Companies with Notes Applications
2. Sources of Notes API Information
3. Local User Groups
4. Notes R4 Database Samples
5. Notes Related Web Sites
6. Mirrors Sites for the Notes FAQ


How do you update a Stored Form in old documents?

First, remove the old form using this technique.
Then, refresh all the affected documents using this technique.


How do you get rid of inactive sessions on a server?

On the server console, execute:

SHOW USERS DROP

This drops all inactive connections on the server. After you do that and do a regular Show Users, you will see no one or only the currently active users who are actually on the system right now. It should wipe out all the old connections, but if you do it and still see a connection with anything but 0 next to it, it's a bad or phantom session and is indicative of other problems.


How do you convert Word files to Notes format?

There is a product called Hyper*Ink (formerly called Lexstyle Publisher) from CoExtant (formerly Pantano Genesis) which can batch convert formatted Word document into hyperlinked Notes documents. Contact them at [email] sales@coextant.com.

Notes:Import Document from Pembroke International also will do this, but cannot automatically generate multiple linked Notes documents for each chapter of a Word document.


How do you fix the server name resolution problem with Netware NDS?

When using SPX as a transport protocol in v4, you can register your Notes server names in the NDS tree and resolve IPX address without having to use SAP. By default, the Notes client installs with both NDS (Netware v4) and Bindery (Netware v3) methods available. The Notes client will first try to resolve using an NDS lookup and then fall back to SAP (bindery) lookup. If your organization is not using NDS or has not registered your Notes servers as NDS objects, then you will receive an error message when Notes tries to look up the server name in NDS.

To correct the problem, select File>Tools>User Preferences from the menu. Click the Ports icon. Select the SPX protocol from the list and click the SPX Options button. On the advanced dialog, select the Advanced Configuration and then select Bindery Services. This will make the v4 SPX client use the same method as the Notes v3 client and should eliminate your problem.


Can Notes be attacked by Viruses?

Here is a useful posting by [email] Christopher Feller:

"...Notes is an entirely different paradigm. One of the reasons viruses and attacks on internet-based systems happen so frequently, is that the initiators are anonymous. They don't have to worry about retribution or punishment. However, you don't attack a Notes server anonymously like a Firewall or FTP server. You can't even begin to touch a Notes server unless someone has created an ID for you. And as soon as an ID exists, there's an electronic trail to follow, I don't care what fields you delete.
Someone creates an anonymous mail-bomb? Fine. I'll just trace through all the servers listed in the RouteServers field to find where the initial mail came from. Then I'll check the RouteTimes/PostedDate and compare that to the Notes Log to see when it was routed through that server. Then I'll check to see who was logged in and bust them.
Worried about attacks on your N&A? Don't give anyone greater than reader access, and control the certifier tightly. Don't let just anyone create replicas/copies on the server. Also, place a mail-paste macro that does an @DocumentDelete in the N&A. (This will keep anyone from routing anything nasty to the N&A by using Mail-In database documents or by setting the mail database destination of a user in the main or secondary N&A book to be the N&A itself.) Finally, mark all documents in the
N&A as read and check the database for unread documents on a periodic basis from the local workspace. If anything new or changed is there (even if it doesn't show up in a view) you'll find it by pressing that Tab key. (For those people who are worried about a disgruntled employee making design changes to documents or forms, inherit the N&A design from an "approved" template nightly and run a nightly background macro to check for documents that have mysterious or "non-approved" form names). Oh, and don't forget to setup statistics and event reporting!

My point is simply this: due to the way Notes was designed, access is always "granted", not implicit. So, no matter what, there's always a record of activity somewhere and there always a way to deny that access.

If you have your security set up sensibly, your logging turned up to the max, and train your users to look at buttons before pressing them (highlight the button and choose Edit->Button) then you really don't have much to worry about. If you ever do encounter anything strange, you'll be able to trace it with the information contained in the offending document. Don't let panic mongers scare you away from Notes!"


How do you set the outgoing domain name in the SMTP MTA on a per user basis?

This technique, which can be used to host multiple domains provided you have unique names across all the domains, applies to the Lotus SMTP MTA 1.05 and higher:

You can edit the short name field in the user's Person document to include the domain name. For example, if your domain is "company.com", you can enter the user's name as "user@another.com" and the mail will be sent with that as a reply address.

To be able to receive mail from more than one domain, be sure to add the other domain to the Internet Domain Suffix field in the Global Domain document.


Why aren't laptop user's database designs being updated?

Check that the Server is given at least designer access to the Local database. A frequent error occurs like this. The database ACL is set up this way:

Default {Editor}
LocalDomainServers {Manager}
OtherDomainServers {Editor}
Admin {Manager}

Since the Server is usually in the group LocalDomainServers, it has manager
access when being evaluated against the Server's N&A Book. The problem occurs
when the Laptop user makes a replica of the DB. On the laptop, the user has a
local N&A book which is used to resolve Group Names when evaluating the ACL
when it replicates with the Server. The Server is usually not a member of the
group LocalDomainServers in that private N&A book, therefore no design changes
are passed when the replication occurs.


How do I set up searching for numbers and punctuation with FT Search?

If you are using the default.stp file, it ignores numbers. You can create a special stp file for use with this database that includes numbers. Just remove the line:

  [0-9]+

and all numbers will index.


If you are looking for numbers in a Number field, numeric fields have to be searched for by specifying this formula in the search window (or by using a Form to search which generates this formula):

  ([SearchField]=value)

Punctuation and other special marks, except for '&', "/", ":", and "." are NOT included in the index so there is no way to search for them. You can never find "C++" no matter how you arrange your query since it isn't "text" and it is not included in the index. You'll have to use the non-indexed search function by holding down <shift> as you click on the flashlight icon. This will bring up the regular search dialog box. Type C++ in there and let it search all documents. When finished, select "Show only selected" under the View menu and you'll see all the documents that contain "C++" in them. Keep in mind the words won't be hilighted like in the FTS, but at least you can identify all the documents.


Is Notes Year 2000 Ready?

From Lotus' Knowledgebase Article#147238:

Lotus Notes is ready for the year 2000. In fact, support for the year 2000 has been part of the Notes architecture from the very beginning of its development. Therefore, all Notes releases, beginning with Release 1.0, fully support all year 2000 date functions, and no human intervention is necessary for Notes to continue functioning correctly when we move into the year 2000.

When discussing the impact of year 2000 dates in Lotus Notes, there are three areas of Notes date functionality to consider. These are:

1. Date entry.
2. Date calculations.
3. Notes server time synchronization.

Below are descriptions of each of these areas and explanations of how Notes handles each:

1. Date entry.

Since Release 1.0 of Notes, it has been possible to enter dates for the year 2000 and beyond simply by typing all four digits of the year. For example, "1 1 2000".

For all Notes releases prior to Release 4.5, if only two digits are typed in for the year, Notes assumes that the user means the date within the base century 1900. For example:

If the date entered is "1 1 20", Notes releases prior to Release 4.5 will internally store the year as "1920".

Beginning in Notes Release 4.5, if only two digits are typed in for the year and the two digits are a value between 50 and 99, then Notes will assume that the year is within the base century 1900. If the two digit year value entered is between 00 and 49, then Notes will assume that the century is base 2000. For example:

If the date entered is "1 1 97", Notes will internally store the year as "1997". If the date entered is "1 1 00", Notes will internally store the year as "2000".

This new feature in Notes Release 4.5 will allow data entry to be more intuitive for users as we move into the next millennium.

The only place where Notes does not make this assumption is with the @Date function. If you enter an @Date formula with a year as two digits, Notes assumes you mean the literal year that is entered. For example, @Date(94;3;16) will evaluate as 03 16 0094, when you probably intended @Date(1994;3;16) which will evaluate as 03 16 94. This is true in all Notes releases, including Notes Release 4.5.

2. Date calculations.

All calculations using pre- and post-year 2000 dates in Notes will execute correctly. Notes' internal TIMEDATE structure stores the dates in such a way that they can be manipulated in formulas in anyway, regardless of the year or any other part of the date.

Notes internally supports up to the year 32767 on 16-bit operating systems (limited by a 15-bit year quantity in our TIME structure), and the year 41247 on 32-bit operating systems (limited by a 24-bit Julian date quantity in our TIMEDATE structure), so it is well prepared not only for the year 2000 but for many millenniums beyond that.

3. Notes server time synchronization.

When a Notes server is started for the first time, it picks up the time from the operating system it is running on and then keeps its own time from then on until the server is brought down again. The Notes server already knows how to manage the year 2000, so it will automatically roll its time from December 31, 1999 at 11:59:59 PM to January 1, 2000 at 12:00:00 AM. The Notes server also knows how to work with leap years and daylight savings time, so both of these will also be handled correctly during the year 2000.


Why can't I access a database design although I have Designer Access?

Make sure View - Show - Design is selected. If this is deselected, the design twist-tie will not be shown.


What keyboard shortcuts are available in Notes?

Note that these shortcuts are for Windows machines. They may be different for Macs, OS/2, or Unix systems.



From a form:
[TAB] Next unread document.
[SHIFT]+[TAB] Previous unread document.
[ENTER] Next document.
[BACKSPACE] Previous document.
[Shift]+[F9] Replaces a user-entered formula in an editable text field with its returned value.
[ALT]+[1] Click the 1st action button, 2 for second, and so on.
[CTRL]+Compose Document Suppresses inheritance when creating new document.





From a view:
[RIGHT ARROW] Hortizontal Scroll Bar.
[INS] Toggles "read" and "unread" marks.
[ALT]+[number N] Click the Nth action button.
[F3] Displays or moves highlight to next selected document.
[Shift+F3] Displays or moves highlight to previous selected document.
[F9] Update current view.
[CTRL]+[SHIFT]+[F9] Update all views in database.
[Shift+Gray Plus] Expand an entire view (Expand All).
[Shift+Gray Minus] Collapse an entire view (Collapse All).
* key on the keypad Expands all descendants of the currently selected document.





From the Workspace:
[`] "Scan for unread mail" from the desktop.
[TAB] "Scan for unread" from the desktop.
[CTRL]+[SHIFT]+Double-Click on Database Shows all views of database (including the hidden ones).
[SHIFT]+Select Databases and then Double-Click Opens up the current view of all the databases into one mixed view.
[SHIFT]+View\ShowServerNames Display the filenames of the databases on the desktop.
[Shift+F9] Updates unread count on current work page.






From anywhere:
[CTRL]+[TAB] Cycles through open Notes windows.
[ALT]+[ENTER] Toggles the Properties Box.
[CTRL]+[M] Create mail Memo.
[ALT]+[F9] Minimize Notes.
[CTRL]+[F9] Restore open Notes windows to non-minimized.
[F5] Log you off of your Notes server, but does not exit Notes.
[F1] Displays context-sensitive Help.


What do you do about forgotten passwords?

There are a couple of methods to deal with this depending on how secure you'd like user accounts to be:
1) Keep a backup of the user ID with a known password in a secure location. However, any encryption keys that the user adds will be lost if this backup file is used when the user forgets his/her password.
2) Don't keep backups and warn the user about what it means to lose a password (all your encrypted files won't be accessible any more, etc.). This also guarantees that the user is the only one who could have sent a mail message (useful in court cases) or done something to a database.
3) Separate the ID file storage and the password knowledge between two different people. This is a safer position than (1). However, if the two people work together, security in Notes can still be compromised.

If you are running 4.1, there is a new feature that will help you use method (1). You can set up an escrow account and when you register a new user, the new ID is sent (mailed) automatically to the escrow agent. This way, you keep backup copies of every ID you make.

There is no way to recover encryption keys from a user ID with a forgotten password!


Why isn't my @DbLookup background macro running properly?

For any @DbLookup or @DbColumn that is run from a backgound macro, you need to put the ReplicaID of the database where the macro is being run into the ACL of the database which is being used for the source of the lookup.

A background macro is executed by $Chronos which doesn't have an ID by itself. That's why it uses the replica ID of the database containing the macro for authentication.

How do you run the Compact process on a schedule?

Here is an example program document you can use. Make sure the Notes directory is in your system PATH.

Basics

Program name: $COMPACT.EXE
Command line: -S 5
Server to run on: ServerName/Domain
Comments: Compact databases with more than 5 percent whitespace.

Schedule
Enabled/disabled: ENABLED
Run at times: 10:10 PM each day
Repeat interval of: 0 minutes
Days of week: Wed, Sat


Can you support multiple SMTP domains using the SMTP MTA?

Yes, look at the FAQ on changing the outgoing domain name for the SMTP MTA.


How do you warn users that a server will be shut down?

Use the Broadcast message from the server console:

  Broadcast "Server will be shut down in 10 minutes"

This will send the warning message to all users using the server.


How do you check the difference between two documents?

For the 32-bit Windows client (NT or Win95), edit the notes.ini file to include this line:

  AddinMenus=c:\notes\nntediff.dll

Shut down your client and re-start it.
Select 2 documents in a view.
Select the new menu option Actions/DifferenceOf2Documents.


How do you fix documents with bad ReaderNames fields?

If you access the database locally on the server, you can reset all the bad ReaderNames fields by using an agent. ReaderNames fields are only enforced when you access the database from the server. This also applies to AuthorNames.


How do you specify a new location for the desktop.dsk file?

You can add a line to the NOTES.INI file telling Notes where to find the DESKTOP.DSK file. By default it looks in the Notes Data Directory. E.g., the following line :

  DESKTOP=C:\NEWDIR\DESKTOP.DSK

will look for the desktop.dsk file in c:\newdir.


How do you add a disclaimer/signature to all outgoing SMTP mail?

1. Open the MTA forms database (mtaforms.nsf).
2. Select Design and the Forms view.
3. Edit the Memo form and add the text anywhere within the form where you would like the text to appear. Be sure to NOT include carriage returns, since the MTA has it's own line wrapping facility (which is set in the Public Name & Address Book).
4. Save the Memo form.

Remember, you must complete these steps in the future when the SMTP template is updated with new SMTP/MTA releases.


What can the Lotus SMTP MTA do to prevent SPAM?

From a member of Lotus' SMTP team:

The term 'SPAM' covers such a broad spectrum of SMTP mail 'attacks' that there is no easy solution to the prevention of 'SPAM'. The MTA provides rudimentary capabilities to deal with 2 types of 'attack'.

1. Relays
These are messages sent to your SMTP server from an outside source that are not destined for a local recipient, but are for another external SMTP address. This results in your SMTP server 'relaying' the message onto the external destination. Before the explosion of the Internet and the use of DNS to provide 1 hop source to destination routing of messages this was an acceptable practice on the Internet. Infact the original concepts relied on it to provide source to destination routing across many interconnected hosts. However the ability to accept and transfer 'Relay' messages brings 2 problems to the modern Internet SMTP host administrator. Firstly it results in the local organization incurring transfer costs to handle messages that have no relation to that organization. Secondly, as SMTP is in general an unauthenticated protocol, it became a mechanism for the distribution of 'SPAM' mail. A host that was available to relay mail could be used as the 'distribution' point for a broadcast/offensive 'SPAM' message. Often the message would be constructed to make it look like it originated from that host domain, making to original distributor virtually anonymous. As a result, most SMTP servers directly connected to the Internet are configured to provide some measure of protection to deny the ability to relay messages through them. The initial SMTPMTA option to prevent relays was provided as a quick 'band-aid' to a growing problem.

The MTA was designed to accept and support the concept of Relay messages. This was achieved by allowing the Inbound message converter to pass any message that is not destined for a local user to the Outbound Work Queue so that the Outbound Transport could route it out. The first 'band-aid' solution was an ini variable, SMTPMTA_REJECT_RELAYS=1. This ini variable switched off the Inbound Converters ability to perform relays. If the converter found a message that was supposed to be relayed, instead it would flag an error and place the message in state that the DRTask could generate a Non-Delivery report. This solution has a number of limitations:
It cannot distinguish relays from external originators that need to be blocked and messages from local POP/IMAP clients that need to be relayed.
Often the Originator address on a Spam relay message is bogus, so the NDRs often failed an ended up DEAD in either the Inbound or Outbound WQ's, which meant more work for the Administrator to have to monitor and clean up after.
The check only occurred after the entire message has been received, which results in the hosting server incurring the cost of reading in the message.
The check only looks for messages that were destined for the Outbound WQ from the Inbound WQ. There is a mechanism of addressing that can cause an MTA to deliver the message to mail.box, and the Router to deliver it back to smtp.box. This method of addressing circumvents this relay check, and is referred to in the internet as '% hack' addressing.

The MTA team had been aware of the potential of '% hack' addressing prior to the need to reject relays, and the MTA already had an .ini variable to handle messages that had an SMTP address that results in a Notes message that will be delivered back to SMTP. This is another 'band-aid' solution. It works, but there are drawback. The ini variable is SMTP_OCH_REJECT_SMTP_ORIGINATED_MESSAGES=1. When the MTA Inbound Converter creates a message in Mail.Box it writes a field called SMTPOriginator to hold the SMTP specific Originator information for NDR purposes. This .ini variable plays off of this functionality.

It causes the Outbound converter to reject any message in SMTP.BOX that has an SMTPOriginator field (i.e originally came from SMTP). This will block the '% hack' relay case in SMTP.BOX. The downside is due to the way Notes does NDRs. When Notes sends back an NDR for a failed delivery it does not send back a new message. It will send back the original message, with all the original fields, but it adds additional information. This means that Notes NDRs to incoming SMTP messages will have an SMTPOriginator field and will be blocked by this .ini variable.

To overcome most of the limitations of the Reject_Relays ini variable the MTA implemented a new mechanism to handle the denial of relays. This is controlled by the SMTPMTA_ALLOW_KNOWN_DOMAINS=1 .ini variable. This allows the MTA to refuse any message which is deemed to be a Relay during the inbound transport session rather than in the Inbound Converter. For each incoming connection, and each incoming recipient the MTA makes a determination regarding the nature of the Connection and the nature of the Recipient, each can either be 'External' or 'Internal'. An 'Internal' Connection can send messages to both 'Internal' and 'External' Recipients. An 'External' Connection can only send to 'Internal' recipients, 'External' recipients will be rejected. The MTA determines the states as follows. The MTA knows which Internet Domains it is responsible for, from the Internet Domain Suffix list in the Global Domain Document. The Inbound Sessions Handlers have access to this list of domains. When an incoming connection is received the Session Handler can obtain the IP address of the host that is connecting to it from the IP stack. The Session Handler then uses the DNS to resolve the IP address into a host name. Once it has got the host name, it compares it to the list of 'local' domains. If the connecting host is in one of the 'local' domains, then the Connection is deemed 'Internal'. If the host name is not in a 'local' domain, or the DNS was unavailable, or unable to provide a hostname, then the Connection is not to be trusted and is deemed 'External'. As the connecting host goes through the SMTP protocol exchange, the Inbound Session handler checks each recipient address against it's list of 'local' domains. If the recipient is for one of the local domains, then it is considered 'Internal', anything else is 'External'. Once both states are know the Inbound Session handler can decide if it will accept that recipient or reject that recipients. This mechanism solves the previous problems:
It has an ability to distinguish between external relays and internal POP/IMAP clients.
It does not need to accept the message content before decided whether it is a relay or not. This reduces the network traffic and means no NDRs to clean up for the Admin.

There are, however, still some potential limitations:
Because it uses DNS reverse lookups to 'validate' an incoming connection, if local POP/IMAP clients have IP addresses that are not in the local DNS, then they cannot be seen as 'Internal'
If the incoming connection is through some Proxy Servers, this may mask the true IP address of the connecting host from the MTA, so that the MTA always sees the incoming host being the Proxy Server. If the Proxy Servers IP address resolves to a local host name, then all incoming connections are considered 'Internal'
Because the Inbound Sessions handlers do not have access to the Router Routing tables, they cannot make a further determination as to whether a '%hack' type address to a local domain is truly an inbound message or a 'Relay'. As a result this option will not prevent inbound relays using a '%hack' address to a local domain, so the previous .ini variable may need to still be implemented to prevent these relays.

2. Attacks
Whilst a Relay is technically an attack, it is primarily an attack against another system, using the local SMTP host as an unwitting carrier. It is also possible that a connecting system may attempt to deliver a message to a local address that is considered an attack. This maybe in the nature of an offensive message, or perhaps an unwanted message. Oftentimes these messages are repeated over and over continually, resulting in a degradation of the local mail service.
These types of attack are harder to prevent ahead of time, as they often have no distinguishing features that separate them from ordinary acceptable messages. There are 2 possibilities to help combat them though.

The first is to attempt to authenticate the connecting host to determine that it is a 'real' SMTP host and not an Internet client attempting to attack the server. Until true Server-Server authentication using a PKI setup is available there are a couple of mechanisms. The MTA provides one of these, however its usefulness is somewhat in question. When a host connects to the MTA, it provides a HELO/EHLO command with it's own hostname as a parameter. Early on it was thought that this could be used to 'authenticate' the connection, as most 'SPAM' attacks used a bogus name at this point. A number of vendors including the MTA implemented a check of this parameter by taking the incoming IP address, looking it up in DNS to get a host name and comparing the result to the HELO parameter. If they did not match then the connecting host is not to be trusted. Over time it has become obvious that this check is only of little value as there is no requirement that Internet SMTP hosts have the necessary reverse lookup entry in DNS. As a result this type of check can reject connections from otherwise perfectly valid SMTP hosts. Each Admin needs to bear this in mind when considering to implement this option. It is enables via the SMTPMTA_HELO_DOMAIN_VERIFY=1 ini variable.

The second option is the provide a mechanism for admins to 'blacklist' connecting hosts/domains that have previously caused problems so that they cannot cause problems in the future. The MTA provides this via the SMTPMTA_Denied_Domains ini variable. This variable takes the path to a text file as a parameter. That text file should contain a list of hosts that the Admin wishes to refuse connections from, one per line. When this is enabled, the first Inbound Session Handler will take this list and perform DNS lookups to turn it into a list of IP addresses, which is then shared with all the other handlers. Each incoming connection is then compared to the 'blacklist' of IP addresses and the connection refused if there is a match.


As can be seen the MTA provides some basic measures for 'Anti-Spam' however it is by no means complete and Admins should look to R5 for a more complete implementation and ongoing mechanisms. Please check the Release Notes for exact details of all the .ini variables, including correct spelling and in what version they were first supported in.


What Virus scanning packages are available for Notes?

* McAfee's GroupShield and GroupScan
* Trend Micro's ScanMail for Lotus Notes
* Group-WG's WatchDog
* Cheyenne's InnocuLAN for Notes
* Symantec's Norton Antivirus for Notes (NT only)


What is configurable in the Lotus SMTP MTA?

Here are a couple of the most frequently asked questions on this subject:

Question: I installed version 1.1 of the MTA but now some mail messages are coming in as a file attachment with an attachment name of "att1.unk".
Answer: The reason is that some mailers inappropriately send messages with a Content-Type of "Plain/Text" (Netscape is the most frequently used mailer that does this) but without a Content-Name; plain text messages should not be specified with this MIME Content-Type attribute. If you want to go back to the way SMTP 1.0x handled it, set "SMTPMTA_INLINE_TEXT_ATTACHMENTS=1" in your notes.ini file.

Question: How do you tell the SMTP MTA to use '.' instead of '_' for space replacements in user names?
Answer: Add "SMTPMTA_SPACE_REPL_CHAR=." to your notes.ini file. You have to make sure your user names do not contain any periods if you use this translation of spaces.

Question: How do you prevent spammers from using your SMTP MTA to send their junk through?
Answer: Add "SMTPMTA_REJECT_RELAYS=1" to your notes.ini file. You can also set "SMTPMTA_HELO_DOMAIN_VERIFY" to a non-zero value to verify that the SMTP mailer represents the domain they claim to be from. And finally, you can set "SMTP_MTA_DENIED_DOMAINS" to point to a text file with a list of domains you want to reject mail from. Note that this only works with Notes 4.6. More information can be found in Technote 159050 in the Notes Knowledge Base.
If you are running SMTP MTA 1.2, you can use "SMTPMTA_HELO_DOMAIN_VERIFY=1" to make sure that the connected SMTP server identifies itself properly (spammers will pretend they are someone else). You can also use "SMTPMTA_DENIED_DOMAINS=<filename>" to specify a newline-separated list of domains that should not be allowed to send mail to your SMTP MTA.

Question: How do you set the default line length for incoming and outgoing mail?
Answer: Add "SMTPMTA_Outbound_Line_Length=xx" to your notes.ini file, where xx is the line length (default is 75). You can also set "SMTPMTA_Inbound_Line_Length=xx" for incoming mail.

Question: How do you make the SMTP MTA check that the omsgcnv and imsgcnv processes haven't stopped?
Answer: If you add "SMTPMTA_ENABLE_STARTUPCHECK=1" to your notes.ini file, it will check for all 5 SMTP processes every half hour and restart any dead ones. This only works in Notes 4.6.

Question: Can you tell the SMTP MTA to use a different port than 25?
Answer: In Notes 4.61 and above, you can add "SMTPMTA_IPPORT=xxxx" to your notes.ini file. This will set the SMTP MTA to use port xxxx.


How do you remove Stored Forms from documents?

Create an agent with the following code:

SELECT $TITLE="Form Name";
FIELD $TITLE:=@DeleteField;
FIELD $INFO:=@DeleteField;
FIELD $WINDOWTITLE:=@DeleteField;
FIELD $BODY:=@DeleteField;
FIELD $ACTIONS:=@DeleteField;
FIELD FORM:="Form Name";

Notes V4 has a new $ACTIONS field that must be also deleted.


Why do users get notified of new mail even though they don't have any?
The database compaction process on the server will cause the new mail flag to be set incorrectly. Turn this off and the false new mail signals should stop.

If the new mail notification indicator stays on, the NewMailSeqNum=X variable in the Notes.ini file also may have gotten out of sync with the server. Shut down Notes, erase the "X" part of the variable and then restart Notes.


What would change the list of servers I see in the Database Open dialog?

When you do a File/Database/Open, Notes will show you the servers for any database replica icons on your workspace. If you have renamed a server, it will continue to show up as long as you have an old replica icon from the old server on your workspace.
If you select "Other...", it will show you all servers known by your home server.


What TCP/IP port does Notes use?

Port 1352


How do you run Notes in "Kiosk" mode?

Adding "/kiosk" to the Notes command line will bring Notes up without menus. Unfortunately, this clips the top of action buttons currently and you can still use the mouse to grab the Notes window, so it is not as useful as it could be.
This appears to be fixed in Notes 4.61 and above.


How do you make backup copies of created user ID's?

In Notes 4.x, the Escrow Agent allows the administrator to have copies of user ID's, server ID's, and certifier ID's copied to a database automatically whenever you register someone, a server or create a certifier. It also stores the password (encrypted) in the document as well.

1) Create a new person called "ID Repository" or something more descriptive.
2) Modify the NAB person document (ID Repository) "user name" field and append "Escrow Agent" to the field.
3) Restart the server.
4) Set the "ID Repository" mail file to have multiple passwords (so two administrators need to be present to open the mail file).
5) When you create user ID's, be sure to set the password to something obnoxious to type in (not something obvious like "password" so the user will change it.
6) Remind the user that if they create new encryption keys, they should give you back a copy of their ID file with a known password if they want a backup made because the escrowed ID will not have these new keys.


What can be done to optimize database performance?

1. Don't have too many views - each time you change/add a document Notes will need to update every appropriate view.

2. Keep views simple - more columns means more calculation. It gets worse if the columns are sorted and worse still if the columns are categorized.

3. Don't use @Today or @Now in selection formulas - the views will never be up to date and the server will be forever recalculating them. If you need to use today's date in a selection formula then have a background macro running each day to set an environment variable in the server's notes.ini and reference this.

4. If you want to display compound information in a view column from multiple fields then calculate it in a hidden document field. The column should then reference this single field rather than carrying out the calculation.

5. To avoid the @DBColumns/@DBLookups used to generate keyword lists, etc.,
being generated at read time use something like:

@If(@IsDocBeingLoaded & !@IsNewDoc; @Unavailable; @DbColumn(""; ""; "By _Category (Main View)"))

for the formula. Editing documents will take just as long but document readers will notice a big improvement. The example above is from a keyword format formula.

6. Use column numbers not field names for lookups

7. If you are doing lots of lookups to multiple columns in a single view then append all of the data in a single column with a unique delimiter string and do a single lookup. The value returned can then be parsed with @Left/@Right/@Mid or @Explode to give you the separate field values.

8. Put 64 Mb of RAM in the server and push the buffer pool sizes to their limits. This is documented in the Knowledge Base.

Why can't users with Depositor access create documents even though I have enabled Public Access on the form?

This can happen if you have any @DbLookups in fields on the form. Even if you enable users to have Public Access to the form and to the views used by @DbLookup, you will have to give Reader access to the Replica ID in the database to the ACL. For example, you would add an ACL entry of "85255CEB:0032AC04" with Reader access.


How do you make a list of all groups a person is in?

Create view in the NAB with a selection formula of "Select (Form = "Group").
Add the field 'Members' in first column.
In the propeties box for the first column, select sorting type 'categorized' and select 'show multiple values as separate entries'.
In the second column, put the field 'ListName'.

This is not recursive, so it won't show a person in a nested group.


Why do new documents not show up in views after a recent server crash?

Running UPDALL -R should fix these views. However, this doesn't work all the time.

When a server crashes, views that were marked for re-indexing and were queued for UPDATE tend to not be re-indexed. That can be a lot of views. Apparently they think they're indexed and don't mark themselves to be indexed again.

Tell anyone who thinks something hasn't been updated to do a SHIFT-F9 while in the view that seems affected (not from their workspace).


How do you turn off Notes crash dumps (notes.rip files)?

Disable Quincy (the crash dump program) by renaming the executable, QNC.EXE in the Notes directory. You can also uninstall Quincy using the command line "qnc -u".


Can you use the SMTP MTA over a dial-up link?

If you have a dedicated IP address and don't have to worry about leaving your phone line connected all the time, this is no problem. You just have to set up NT or Win95 to automatically redial if the line gets disconnected. Your system is essentially on the Internet.

However, if you have a dialup PPP account with dynamic IP (what most ISP's provide), it is more complicated. You have do several things:
1) Set up Win95 or NT to automatically dial when your Notes server needs to connect to the Internet. Do this by testing it with MSIE or Netscape.
2) Configure the SMTP MTA. Test sending mail and see if Win95 or NT automatically dials up and sends mail to an Internet address.
3) Ask you ISP to save all your mail in a multidrop POP3 account at their site. Your ISP should virtual host your domain (company.com) and hold all mail going to it. Get a copy of POP3Fido and configure it to retrieve mail (this should cause Win95 or NT to autodial when needed).

If you use OS/2 or are having problems with step (1), it is easier to use a Windows-based proxy such as WinProxy. These proxies can be set up to automatically dial the Internet. An additional benefit of this method is that they will also give your company dial-on-demand access to the web or to Usenet newsgroups.

Notes R4.6 adds dialup SMTP support. However, it is not documented clearly that your ISP has to give you a static IP address and your ISP also has to support ETRN on their mail server.

The reason this is so complicated is that SMTP is a "push" protocol (in Notes parlance). One of the destination SMTP servers is always expected to be available. Usually, your ISP's will set up their SMTP server as a backup in case your system is down. If you bring up your connection "for long enough", the ISP's SMTP server will send all the mail it has collected for you, but this still requires a dedicated IP address. This technique is not as reliable as a "push" (outgoing mail via SMTP MTA), "pull" (via a POP3 account) technique.


Can I set the default ACL on the N&A Book to Reader?
Notes has been designed to have the default ACL set to Author with no create or delete privileges. Without this, people cannot edit the items in their person document like phone number, location, signature, picture, etc. They also cannot delete the ID file from the N&A book after installation. And worst of all, they cannot edit any groups that they have been given ownership of. You should make the default ACL set to Author (with both delete and create turned off).

Can you keep multiple versions of Notes on the same system?

Yes. On an install of a new version, you should:
1) Put the \Notes directory in your PATH.
2) For major revisions (3.x -> 4.x -> 5.x, etc.), keep a separate copy of the \Notes\Data directory because the Notes internal database format changes between each version; new major versions will upgrade old database versions to the latest which can then no longer be read by the old versions. You can point to the appropriate data directory by editing your notes.ini file; you will only need one per major revision (NoteData.3, NoteData.4, etc.)
3) After the install, move the notes.ini file into the \Notes directory.
4) Before installing a new version, rename the directory of the old version to something else (e.g., \Notes to \Notes.463).
5) Install into the same non-renamed directory (e.g., \Notes), but before doing this, copy your desktop.dsk file into this directory so it can be upgraded if needed.

To use a specific version:
1) Make sure you are not running anything from \Notes (e.g., Notes Single Logon which is nsl.exe, the mail check in R5, the Notes client, etc.)
2) Rename the current \Notes directory to whatever version (e.g., \Notes to \Notes.463) it was.
3) Rename the directory with the version you want to \Notes (e.g., \Notes.50 to \Notes).
4) Start Notes.

You have to keep the same directory structure because in later versions of Notes, there is information in the registry related to OLE automation. If you use separate directories for each version, OLE automation may not function correctly.

With the caveat about OLE automation, you can run multiple versions simultaneously if you:
1) do not put the \Notes directory in your PATH
2) run the nlnotes.exe (or the appropriate executable for your platform be replacing the first character in the filename) instead of running notes.exe
From Olivér Zsigmond (Oliver_Zsigmond@lotus.com) comes this tip on how to run the R5 server locally with multiple clients:

Rename dirs of your existing versions of Notes R3, R4.x as described above.
Move your NOTES.INI into the appropriate NOTES.EXE dir.
Modify the Directory line in NOTES.INI to show the appropriate DATA dir.

Install Domino R5 to \lotus\domino
Install Notes R5 All Clients to \lotus\notes

Both directories will have their own NOTES.INI file and DATA dir.

Start Domino server and complete the setup.
Start any of the Notes clients (R3,R4 or R5) from its directory and you can use the local R5 server. You can stop the client and start any other one without stopping the server. The new rules are that you can start only one client and you can't start the client from \lotus\domino because if you stop this client, it will stop the Domino server as well.


What programs will back up Notes databases without needing a Notes server shutdown?

* Cheyenne ArcServe has a Notes agent which lets it back up open databases. The agent requires a "work area" of the size of your largest Notes database because it creates a replica of a database into a separate directory before backing up that database.
* IBM's ADSM will back up open files and can back up databases incrementally.
* Veritas's Backup Exec with the Open File Option (they also have a Domino agent).
* Unix's tar (and ports of it to other platforms like NT and OS/2) will back up open files.


How do you change the mail file design to use the Notes 4.5 mail template?

If you would like to convert all the user mail databases at once, do this:

  load convert mail\*.nsf StdR4Mail mail45.ntf

This replaces the databases using the StdR4Mail template with the template in the mail45.ntf file.

However, this will delete all the user's private views or folders unless you tell the users to look at the properties on each of their private views and folders and make sure that "Do not allow design refresh/replace" is selected for each of these.

If you add the "-s" parameter, it will preserve any changes a user has made to the design:

  load convert -s mail\*.nsf StdR4Mail mail45.ntf


How do you minimize Notes rollout cost?
If your application is just an information publication application, look at the Notes to Web publishing programs and the Domino support built into Notes 4.5. This approach will also allow your Notes information to be published to all Internet/Intranet users. More information on these programs can be found here.

If you just want to use the Notes applications which are bundled with Notes Express (now known as Notes Mail), using Notes Express from Lotus will let you deploy Notes for approximately $50 per seat in quantities. Any custom applications that use the Lotus API directly can also be run from Notes Express.

If you wish to develop custom applications, but not allow most users to develop applications, Notes Desktop is a run-time version which available for $79 per seat in quantities.

Finally, if your users will always be using web browsers and POP3 clients, user licenses are only $30.


How do you upgrade the max size of a database?

If you initially created a database with a maximum size of 1GB or 2GB, you can increase the maximum database size to 4GB by executing this command at the server console:

  load compact <filename> -M

where <filename> is the file name of the database relative to the data directory.


Can you open a database automatically when Notes starts?

Yes, you can specify a parameter to the Notes executable on the command line or to the desktop icon in the form of <server>!!path\nsffilename. For example

    server1!!mail\jblow.nsf

would open the mail file jblow.nsf when Notes first starts up.


How do you get Notes to rebuild corrupted views?

From the server window, run:

load updall dbname -C
load updall dbname -R

Dbname is optional. If omitted it will operate on all db's.
-C builds indexes for all views that have not already been built.
-R rebuilds indexes for all views that have already been built.


Who can I call to find my local reseller and licensing information?

You can call Lotus at 1-800-782-7876 in the United States.


Can you check for mail without leaving Notes running?

These are freeware utilities that let you do this in Windows.

CMS Mail Monitor
This program shows the mail sender and lets you enter a selection formula for which mail will trigger popups. It is available [ftp] here.

Alert!
There is also a non-free Professional version which is able to monitor any database on any server you like and shows the number of unreads of each database in a window. The demo version is available [ftp] here.

Mail Monitor
This is not a freeware utility. It is available from Rein&McBride.

NotesAlarm
This is freeware, but only runs on Win95. It is available from Polo Sardinaloil's
web page.

WinBiff
This is shareware and is available from the WinBiff home page.


How do you fix the Mail Archiving Agent so it keeps documents in the right folders?

There is a sample modified database on The View's web site. What it does is create a categories field with a list of the folders the document belongs in so it can carry the folder location information with the document when it is moved into the archive.


How do you manage ACL information across an organization?

Notes R4 allows you to set a database's properties so that ACL's are consistent across all replicas.
Notes R5 has built in tools for updating the ACL's across multiple databases.

Percussion Software has a product called Server Admin Plus that will also let you manage and audit ACL information.

Candle also has a system administration tool.

IVES Technologies has a product called ACL Reporter Updater which is a platform independent administration tool that provides security management for enterprise-wide Lotus Notes/Domino networks.


Can fields be added to the N&A Book?

There's no problem with adding fields and views, but don't change anything that is pre-existing. Do all your work in a template, and be very careful with the management of that template. There are two dangers:
(a) losing your modified template due to inadvertant replication from a newly installed server that has a standard NAMES.NTF that is newer than your custome version, and
(b) having two different templates for the NAB on different servers such that $DESIGN on each server re-inherits conflicting designs every night causing a "Design Storm" that can bring your whole network down.

Do not name it NAMES.NTF, or it may be overwritten by a software upgrade. Make sure that the template name is not the default (StdNotesAddressBoook). You can either make it a replica of the original NAMES.NTF, or a copy.

If it is a replica, be sure to remove the original, be sure to let it replicate to all servers, and be especially sure that any time a new Notes version is loaded that you merge any changes in the new version's NAMES.NTF into your template and then delete that NAMES.NTF from your server before you allow the upgraded server to replicate with any other server.

If it is a copy instead of a replica, it is best that you uncheck the setting that allows replication of the template name for your NAB and make sure that only one server in your organization is set up to inherit the NAB design from your modified template.
Just for insurance it might be a good idea to use the ACL or selective replication to insure that your main hub server never accepts NAB design changes from any other server.

For Notes R4 and R5, the preferred way of adding fields to the NAB is to use subforms.


How do you make the infobox reappear if it doesn't show up?

From Lawrence Wagner (lwagn2@dwp.ci.la.ca.us):

METHOD #1:

Using the keyboard:

1. Select File, Database Properties.
2. Hold down the ALT key and press the spacebar.
3. If a menu appears, select Move. If not, type the letter "m".
4. Use the arrow keys (i.e., the up arrow) on the keyboard to move the InfoBox back onto the screen. You should eventually see a dotted line in the form of a rectangle. Once you do, press ENTER. The InfoBox will reappear on the screen.

METHOD #2:

The NOTES.INI variable that is responsible for the position of the InfoBox on the screen is:

Win32InfoboxPos=

If you cannot find the InfoBox, modifying the values in the NOTES.INI to will also make it reappear. The values in this parameter refer to x, y coordinate locations. By changing these to numbers that fit within the pixel resolution (for example, 800x600), the InfoBox will reappear. Examples:

Win32InfoboxPos=441 79

or
Win32InfoboxPos=333 261


How do you change the available letterheads in mail?

Letterheads are stored as "Subforms" in your mail database. Mail then uses them on the memo form as a computed subform. The action that allows the user to choose one of the letterheads, adds their choice to an environment variable called "DefaultLogo."

To change the letterhead, you need to add the subform - then add the subform to the form "Letterheadchooser" so it can be selected. The changes do need to be applied accross the organization, otherwise if a recipient does not have the subform they will get an error message on opening your mail "Subform xxxx not found".

An easier way to create a custom Letterhead for you or your users is to create personal stationary instead. It will allow you to create a message and use it as much as you want. With this you get a rich text field at the top of the and bottom of your memo. This stationary template will reside in the drafts folder.


How do you change the Lotus SMTP MTA space replacement character to '.'?

This line should be added to your notes.ini file:

SMTPMTA_SPACE_REPL_CHAR=.


How do you put a Notes Database on a CD?

From Glenn.Thibert@thehartford.com:

The following steps are necessary to put a database onto a CD or other read-only media:

1. Select the database and choose Design - Views and make sure that all views are unhidden (i.e. do not have parentheses around their names). It is important to temporarily unhide the hidden views so that the view indexes for these views can be created (see Step 2 below).

2. Open the database and press CTRL+SHIFT+F9. This key combination will rebuild all of the views in the database. This includes both open and hidden views, as well as server-based or local databases. It is important to build the view indexes before copying the database to the CD or other read-only media as, if they are not created and stored in the NSF file prior to adding it
to the read-only media, Notes will attempt to create them and will not be able to because it cannot write to the media.

Note: If a view is not built, pressing CTRL+SHIFT+F9 will cause Notes to build the view. If the view is already built, pressing CTRL+SHIFT+F9 will cause Notes to update the view, not rebuild it.

3. Create the full-text index for the database if you intend for the database to be queried using Notes' full-text indexing capabilities. You can do this using the File - Full Text Search - Create Index command. This index must be created prior to putting the database on the read-only media for the same reason described for view indexes in Step 2 above.

Note: Most CD mounting software conforms to the ISO 9660 standard which does not allow for periods in directory names. When creating full-text indexes in Notes, it by default creates a directory with the extension .FT (period - FT) which is against the ISO 9660 regulations. For example, if your database is called DATABASE.NSF, then Notes will create a subdirectory called \DATABASE.FT underneath the directory which contains the file DATABASE.NSF.

To workaround this issue, do the following

a. Create another directory which has the same name as the database, but with no extension (i.e. \DATABASE instead of DATABASE.FT). This new directory name must be the same as the database name.

b. Copy all of the files created for the full-text index from the original directory into the new directory.

c. Delete the full-text index files from the old directory name (the name with the .FT extension) and remove the directory from the system.

Notes will now see the new directory and use the full-text index files inside of it. It does not require the .FT extension to be on the directory name. The .FT is only used as a naming convention when creating the directory for full-text indexes so that those directory names wouldn't show up along with the other directory names in the File - Open Database dialog box.

4. Do an operating system level copy (such as using the DOS or OS/2 COPY command) of the .NSF file from the writeable media which you are currently using onto the media which will be used to press the CD or other read-only media. Be sure that you do an operating system level copy during this step and not a File - Database - Copy from within Notes as using Notes to copy the
database will remove the view indexes.


Also, be aware that Notes databases on a CD can only be viewed by the same major version of Notes that the Notes database was indexed with. The view index and full text index are improved with each major version, i.e., R5 can't read R4 DB on CD, etc. To work around this with old CDs you may still want to view, you can copy the .nsf file to your local system, follow the procedure above, then copy all the files onto a new CDR because CDRW drives are so inexpensive now.


What is involved in deploying Notes to International users?

From a posting by [email] Kevin Urbanek:

"There are some questions you will need to answer before a decision can be made. First the legal stuff. Legally, a NA ID file can not leave the US or Canada (unless the US State Dept grants you an exception). NA Notes servers can talk to Non-NA Notes servers just fine with one exception, encrypion keys (all keys would need to be International for them to be used worldwide). Note that not all countries allow encrypted data or have rules/laws governing encryption.

Some questions:
1. Do your applications and/or users use encryption regurally? BTW: make sure to check out encryption laws in the different countries (France,Russia South Korea and others have laws governing encryption and the keys)
2. Do your users travel internationally? (i.e a NA Notes ID travels to Europe)

If you want to keep your NA setup that you currently have, when you setup the International users/servers, you will need to create a new Organizational certifier that is International. Even though you can create an International ID from a NA certifier, this International ID still carries enough of the NA encryption info (I do not know exactly what part) to make it illegal to export. So, you would end up with 2 Organizational certifiers, which means you need to cross certify the organizations. You can still use one Domain if you wanted. Depending on number of users, you may want to look at 2 Domains, one NA and one International.

If you answered "Yes" to the above questions, then you might want to think about migrating to World Wide Security (International version) or appy to the US State Dept. for an exemption. If you look to migrating, make sure you plan the migration of IDs and also review the Notes applications you have for encyption and sections. If you keep the naming conventions you have in place, Reader and Author names should not be a problem."


How do you create a database that is usable as an address book for name lookup?
You only need to have the views ($Users), ($PeopleGroupsFlat), and ($PeopleGroupsHier) in your database. You also need the ($NamesFieldLookup) view if you want people to be able to begin typing the name in the To: field and have Notes find it automatically in the address books and fill in the rest.

In the person form, you must include the following fields:

  FirstName (Type: Text)
  LastName (Type: Text)
  FullName (Type: Names)
  MailAdress (Type: Text)
  Type (Type: Text) with default value "Person"

Then add the database to the notes.ini file as a cascaded address book.


How do you move databases onto a different drive without the user knowing about it?

You can use a directory link to put all the databases into what the user sees as a subdirectory in the Notes client. In the Notes data directory, create a file named <subdir>.dir where <subdir> is the name of your subdirectory. The first line in the file is a directory name which can include a drive letter (e.g., "e:\data2"). Lines after the first line are hierarchical names for people that can go through this directory link ("e.g., */MyCompany") so you can use directory links as a security tool.

You can also use a database link. To do this, move the database to your new directory. In the Notes directory where the database used to be, create a file with the same filename as the old database. In this file, put the path to the new location of the database (e.g., "e:\data\db.nsf"). When Notes accesses this file, it will automatically look for the database using the path you specify.

If you are using OS/2, you can install the Toronto Virtual File System (TVFS) from one of the many OS/2 ftp archives. This file system allows you to merge directories and files into a "virtual" directory that you can then use for the Notes data directory.

Note that all of these methods will slow down file access a little, but the slowdown should be negligible.


[<a name="NT00000FC2">How can I use a POP3 client, such as Netscape or Eudora, to
access my mailbox in Notes?
</a>]

There are two parts to this:
1) On the server, load the POP3 Server task with "load pop3"; you can also add it to your "TASKS=" line in your notes.ini file if you'd like.
2) Create a person document for the user and fill in the HTTP/Internet password. The user will have to log in using their user name (fully qualified if you specify a Notes domain) and this password in their POP3 client.

Note that even if these users do not have a Notes ID, there is a Lotus per user charge of $30 for each Domino/POP3 mail user.


How do you prevent groups from being expanded when sending mail?

The group expansion only happens for groups in your personal NAB. You can do the following to disable this expansion when sending mail:

Modify your memo form to include a hidden field named "ExpandPersonalGroups" with Text type and Computed when Composed with a value of "0". This will cause personal groups to NOT be expanded. Changing the value to "1" will cause the groups to expand.


How do I get rid of the encap2.ond attachment on outgoing Internet mail?

These attachments are used to send Notes rich-text-format messages to other Notes users across the Internet.

In the SMTP MTA section of your server document, set the Message Content field to "Users without Lotus Notes"; you probably have this set to "Users with Lotus Notes". Your users can still manually send fully-formatted messages to Notes users via Internet mail by using Actions/SpecialOptions when creating a new mail message.


How do you shut the server down for backups?

If you are running Notes as an NT service, look at this FAQ instead.

You can use the following command to tell the Notes server to shut down:
notes server -quit
After your backup is complete, issue this command to restart the Notes server:
notes server


What Netware address does a Notes server use?

When using SPX, the server advertises with a SAP (Service Advertising Protocol) address of hex 039B.


Can you synchronize unread marks if a user has multiple machines running the Notes client?

Yes, put this in the notes.ini file on all the client machines you use:

  REPLICATOR_SYNC_UNREAD=8

This will synchronize unread marks once every 8 hours. This can slow down replication a lot and only works on Notes 4.13, 4.51 and higher. The problem is fixed in Notes 4.6 and above, so you won't need this setting.

Another technique the user can use is the following:
1) Unstack the replica icons under the view menu.
2) Select the two databases on the workspace by clicking w/ the Shift key depressed.
3) Choose Edit/UnreadMarks/ExchangeUnreadMarks.


How do I add additional N&A books to the address lookup dialog?

In your notes.ini file, you should modify the line that reads "Names=NAMES.NSF" to read "Names=NAMES.NSF,MYNAMES.NSF". This will cause Notes to look up names in both the NAMES and MYNAMES N&A books.

How do you change the password on the Certifier ID?

* Click File/Tools/ServerAdministration from the menu.
* Click Administration/IDFile from the menu.
* Select the Certified ID.
* Click Set Password.


Are there any large-scale deployment guidelines?
For large-scale Notes deployment, standards should be defined for:
* Notes network topology & replication strategy
* Hardware and software configurations
* Hardware and software installation guidelines
* User, group, and server naming scheme
* Notes mail integration strategy
* Notes & non-Notes data integration strategy
* Server management guidelines
* Operations guidelines
* Security and ACL guidelines
* Application design guidelines
* Application implementation guidelines
* Training guidelines
* Support guidelines
* Staffing requirements
* Group naming standards
* ACL standards
* Database location standards
* Establishing test, development and production environments
* Name and Address Book control
* Centralization or distributed ID creation
* Replication strategy


How do you update the SmartIcons on all your users' workstations via LotusScript?

If you put the following code in a button in an email message and attach all the icon files to the same message, your users can update their SmartIcons by simply clicking on the button when they receive the email:

     '======================================================================
     ' Code Documentation
     '======================================================================   
     'Originally Written By: James Fox @ Com Tech Communications
     'Originally Created On: 1/3/97
     'Last Updated By: James Fox
     'Last Updated On: 1/3/97
     
     '======================================================================
     ' Declare Variables
     '======================================================================   
     Dim session As New NotesSession
     Dim ws As New NotesUIWorkspace
     Dim uidoc As NotesUIDocument
     Dim doc As NotesDocument
     Dim rtitem As Variant
     Dim iconPath As String
     Dim retvalue As Variant
     Dim fileName As String
     On Error Goto errorRoutine     
     '======================================================================
     ' Warn User what is going to happen
     '======================================================================          
     x = Messagebox("SmartIcon Installer is about to setup the new Com Tech SmartIcons.  Your current universal SmartIcon set will be overridden with the new SmartIcon set.  Your original set will be backed up to a file called universe.bak.  Press OK to Continue", 1 + 64 + 0 + 0,"SmartIcon Installer")
     If x <> 1 Then
          x = Messagebox("SmartIcon Setup has been Aborted  Thank you.",0 + 48 + 0 + 0,"SmartIcon Setup")
          End
     End If
     
     '======================================================================
     ' Get and Set Icon Path
     '======================================================================          
     iconPath = session.GetEnvironmentString("WinNTIconPath", True) + "\"
     Chdrive Left(iconPath,3)
     Chdir iconPath 
     '======================================================================
     ' Backup current universal Set
     '=====================================================================
     fileName = Dir$(iconPath + "universe.bak", 0)
     If fileName <> "" Then
          Kill iconPath + "universe.bak"
     End If     
     Name iconPath + "universe.smi"  As iconPath + "universe.bak"
     
     '======================================================================
     ' Detach Files in memo (overwriting existing files)
     '=====================================================================     
     Set uidoc = ws.CurrentDocument
     Set doc = uidoc.Document     
     Set rtitem = doc.GetFirstItem( "Body" )     
     notesEmbeddedObject = rtitem.EmbeddedObjects
     If ( rtitem.Type = RICHTEXT ) Then
          Forall o In rtitem.EmbeddedObjects          
               objectName = o.Name
               fileName = Dir$(iconpath + objectName, 0)
               If fileName <> "" Then
                    Kill iconpath + fileName
               End If     
               Call o.ExtractFile(iconPath + objectName )
          End Forall                                        
     End If
     
     '======================================================================
     ' Notify User of SmartIcon Installer Status
     '=====================================================================          
     x = Messagebox("SmartIcon Setup has completed Successfully.  Your original smartIcon set has been saved as Universe.bak.  Please close and restart Lotus Notes to use your New SmartIcons",0 + 64 + 0 + 0,"SmartIcon Setup")
     End     
     
     '======================================================================
     ' This is the general error routine
     '=====================================================================     
errorRoutine:
     x = Messagebox("SmartIcon Setup is Incomplete.  Please advise MIS via e-mail.  Thank you.",0 + 48 + 0 + 0,"SmartIcon Setup")
     Name  iconPath + "universe.bak"  As iconPath + "universe.smi"
     End
End Sub


How do you add Quoted Reply support to Notes' mail templates?

Quoted replies let you precede each line of the mail you are replying to with a ">"; it is a standard way of indicating what you are replying to when replying to Internet mail (similiar to how people use color to indicate their replies in Notes). Here is a button you can add to the forms of the standard mail templates. Add an Action Button called "Quoted Reply" to the following forms: Memo, Reply, Reply with History. This button is hidden when: Previewed for reading, Previewed for editing, Opened for editing. The limitation is that it can only quote up to around 15K worth of text because of LotusScript's limitation with GetFormattedText.

Put the following script in the Click action:

Sub Click(Source As Button)
  Dim uiws As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument
  Dim doc As NotesDocument
  Dim uidocReply As NotesUIDocument
  Dim rtitemBody As Variant
  Dim sBodyOriginal$
  Dim sBodyConverted$
  Dim vntMailDbFile,vntMailDbServer
  Set uidoc=uiws.CurrentDocument
  Set doc = uidoc.Document
  Set rtitemBody=doc.GetFirstItem("Body")
  sBodyOriginal=rtitemBody.GetFormattedText(False,0)
  vntMailDbServer=Evaluate("@Subset(@MailDbName;1)")
  vntMailDbFile=Evaluate("@Subset(@MailDbName;-1)")
  Set uidocReply=uiws.ComposeDocument(Cstr(vntMailDbServer(0)),Cstr(vntMailDbFile(0)), "Reply")
  sBodyConverted=ManipulateReplyText(uidoc, sBodyOriginal)
  Call uidocReply.FieldSetText("Body", sBodyConverted)
End Sub

Function ManipulateReplyText (Source As NotesUIDocument, body As String)
 'Adding > to the begining of each line of the "History text" and
 'Aligning the text Left (wrapping)
  Print "Formatting ""History"" text"
  Dim bd As Variant
  Dim note As NotesDocument
  Dim Header As NotesItem
  Dim dateItem As NotesItem
  Dim InFrom As NotesName
  Dim GetInternetFullName$, HeaderString$, pos%, tmpString$, pos1%, dont%,tmp$
  Dim y%, x%, b%, xx%, xb
  Set note=Source.Document
   'dividing the text to lines and addding the > sign
  If note.hasitem("$AdditionalHeaders") Then
     'starting here: inbound messages seem to have $AdditionalHeaders
    Set Header=note.GetFirstItem("$AdditionalHeaders")
    If Header.values(0) = "" Then
       'GetInternetFullName=note.InheritedFrom(0)
      GetInternetFullName=note.From(0)
      Goto Continue
    End If
  Else
    If Not note.HasItem("tmpAdditionalHeaders") Or
           note.tmpAdditionalHeaders(0)="" Then
       'GetInternetFullName=note.InheritedFrom(0)
      GetInternetFullName=note.From(0)
      Goto continue
    End If
    Set Header=note.Getfirstitem("tmpAdditionalHeaders")
  End If
  HeaderString=Header.values(0)
  pos=Instr(HeaderString,"From: ")
  tmpString=Mid(HeaderString,pos+6)
  pos1=Instr(tmpString,"<")
  If pos1=0 Then 'The full name will appear in (...)
    pos1=Instr(tmpString,"(")
    tmpString=Mid(tmpString,pos1+1)
    pos1=Instr(tmpString,")")
    GetInternetFullName=Mid(tmpString,1,pos1-1)
    dont=True
    Goto Continue
  End If
  tmpString = Mid(tmpString,1,pos1-1)
  pos=Instr(tmpString,|"|)
  If pos<>0 Then
    tmpString=Mid(tmpString,pos+1)
    pos=Instr(tmpString,|"|)
    GetInternetFullName=Mid(tmpString,1,pos-1)
  Else
    GetInternetFullName=tmpString
  End If

Continue:
  Set InFrom=New NotesName(GetInternetFullName)
   ' and starting here: I found that inbound messages had a PostedDate item, Not tmpSentOn
  If note.HasItem("tmpSentOn") Then
    postDate = note.tmpSentOn(0)
  Else
    Set dateItem = note.GetFirstItem("PostedDate")
    postDate = dateItem.Text
  End If
  tmp="On " & postDate & note.tmpSentOn(0) & " " & InFrom.Common & "
wrote:" & Chr(13) & Chr(10) & Chr(13) & Chr(10) & ">"
  y=1
  b=1
  For x=1 To Len(body)
    xx=Asc(Mid(body,x,1))
    If x<>Len(body) Then xb=Asc(Mid(body,x+1,1))
       'Now that we know the current and the next characters we can consider whether they will cause a line feed, so we can insert our ">".
      If xx=10 Or xx=13 Or xx=11 Or xx=12 Then
         'if this combination occurs then we skip the next one so we don't LF twice.
        If xx=10 And xb=13 Or xx=13 And xb=10 Then
          x=x+1
          tmp=tmp & Chr (xx) & Chr (xb) & ">"
        Else
          tmp=tmp & Chr(xx) & ">"
        End If
        b=1
      Else
        tmp=tmp & Mid(body,x,1)
        b=b+1
      End If
  Next
  ManipulateReplyText=tmp
End Function

How can you have multiple users on one workstation?

Each user has to have a separate notes.ini file and desktop.dsk file. There is a freeware utility called SmartSwitcher that does all this for you and provides a nice user interface. It can be picked up by clicking [ftp] here. This only works for Notes 3.x

A few settings (like workspace textured background) are not preserved for Notes 4.x users in SmartSwitcher. There is a commercial utility named MultiUser Logon Utility from Rein&McBride that does handle Notes 4.x.

Another commercial utility that reads the ID files from a database is SwitchID from Sollazzo Consulting.

You can also use location documents in Notes 4.x and higher. Important caveats: 1) users share the same desktop so one user can rearrange icons/bookmarks and totally confuse the other users, 2) they will get false "you have new mail" indications, and 3) the user ID files for all the users will be in one location.

Here are some tips from Laurence Wagner (lwagn2@dwp.ci.la.ca.us) on how to do this:


Do a normal install for the first user, then do the following:
1. Change the User Preferences
Select File / Tools / User Preferences from the menu.
In the Navigator panel, with icons labeled "Basics, International, Mail, and Ports", click on Basics.
There are four check boxes to the immediate right of the Basics icon. Select the box labeled "Prompt for location".
Now when Notes is re-started, it will prompt the user to select a named location document. The original location documents given with Notes are named for a variety of network connections that these users will not need to use, but do not delete them.

2. Copying the Notes ID files to the Workstation
Get these files from your Notes admin. These can go to the Notes\Data directory or a network drive, as long as it will be available to your users. Once on the workstation, each person should log in and reset their password from the default value. This can be done after the location documents are created for each person.

3. Add an action button, labeled "Make Location Doc", to the People view of the LADWP Name and Address Book. Switch to the user's ID file before you run this. The code for the button is as follows:

Sub Click(Source As Button)
  Dim session As New Notessession
  Dim notesdirectory As String
  notesdirectory = session.GetEnvironmentString( "Directory", True)
  Dim keyfilename As String
  keyfilename = session.GetEnvironmentString( "KeyFilename" , True)
  Dim whois As String, realwho As String
  Dim workspace As New NotesUIWorkspace
  Dim doc As NotesUIDocument
  Dim uidoc As NotesUIDocument
  Set uidoc = workspace.EditDocument(False)
  Dim item As NotesItem
  Dim first As String, last As String, mailserver As String, mailfile As String
  Dim mailserver1 As String, mailfile1 As String
  Dim short As String
  Dim short1 As String
  Dim udir As String
  Dim full As String
  Dim ppass As String
  Dim thisdb As NotesDatabase

  whois = session.CommonUserName
  realwho = session.UserName
  Set thisdb = session.CurrentDatabase
  Set uidoc = workspace.EditDocument(False)
  first = uidoc.FieldGetText("FirstName")
  last = uidoc.FieldGetText("LastName")
  short = uidoc.FieldGetText("ShortName")
  mailfile = uidoc.FieldGetText("MailFile")
  spaceposition = Instr(1,mailfile, "\")
  short = Mid( mailfile, spaceposition + 1)
  mailfile1 = "mail\\" + short
  mailserver = uidoc.FieldGetText("MailServer")
  If first <> "" Then
    full = first + " " + last
  Else
    full = last
  End If
  Call uidoc.Close
  Print "got Person data"

'  Build new rec
'
  Set uidoc = workspace.ComposeDocument ( "", "names.nsf", "Location" )
  Call uidoc.FieldSetText("Name",full)
  udir = notesdirectory
  short1 = keyfilename
  Call uidoc.FieldSetText("Userid", udir + "\" + short1)
  Call uidoc.FieldSetText("Domain","LADWP")
  Call uidoc.FieldSetText("DST","1")
  Call uidoc.FieldSetText("Enabled","0")
  Call uidoc.FieldSetText("NameLookupPref","2")
  Call uidoc.FieldSetText("ExhaustiveNameLookup","1")
  Call uidoc.FieldSetText("Images","0")
  Call uidoc.FieldSetText("LocationType","0")
  Call uidoc.FieldSetText("MailFile", mailfile)
  Call uidoc.FieldSetText("MailServer", mailserver)
  Call uidoc.FieldSetText("Source","*")
  Call uidoc.FieldSetText("TimeZone","8")
  Call uidoc.FieldSetText("WebRetriever","Netscape Navigator")
  Call uidoc.Save
  Call uidoc.Close
'
'     Add the mail database to the workspace
'
  If whois = full Then
    spaceposition = Instr(1, mailserver, "/")
    If spaceposition = 0 Then
      spaceposition = 30
    End If
    mailserver1 = Left$( mailserver, spaceposition - 1)
    Call workspace.AddDatabase( mailserver1 , mailfile1 )
    Messagebox "the mail database for: " & full & Chr(10)  & " has been added to the workspace, and " & Chr(10) & "Location
Document added to Address Book"
  Else
    Messagebox "Location Document for: " & full & " added to Personal Address Book"
  End If
End Sub


Can you have specific notes.ini files per user?

You can modify your Notes startup icon to use this as the command line:

  <path>notes.exe =<path>notes.ini

This uses the specified notes.ini file. You can then place this with a user's personal data files on a file server.


How do you change how long logs are kept in log.nsf?

There is a LOG= setting in the NOTES.INI. You specify
LOG=<logfile name>,<logging enable>, 0,<days to keep documents>,<document size>

Do not set document size too large or the server will not be able to compact the log database very well.


How do you transfer data between Notes and other databases?

There are a variety of tools that allow Notes to bidirectionally share data with relational databases. Here are a couple of reviews to get you started:

* Dave Campbell's Review
* Laurance Stuntz's Review


How do you set up remote users with a local replica of a new database?

Create a mail message to the remote users with
1) a copy of the database as an attachment
2) a database doclink

Also in this mail message, add some instructions on how to detach the attachment and where to place it (in the Notes data directory). After the attachment has been detached, the instructions should ask the user to click on the doclink. This will search for the database replica locally and open it; it will also place the database on the replication workspace page.
If the attachment is large, you should warn remote users that you are sending it to them so they don't think that the replication is hung.


How do you refresh Private View designs on clients?

Delete the database icon from the user's workspace and re-add it. Deleting the database will cause all the Private Views to be removed. When the user re-opens the database, new Private Views (with the updated design) will be created.

You can do this via a macro that is sent to users via email:

@Command([WindowWorkspace]);
@Command([FileOpenDatabase];........);
@Command([FileCloseWindow]);
@PostedCommand([EditClear]);
@PostedCommand([FileOpenDatabase];.......)


Why does my mail say it is sent from someone else?

If you have the calendar profile (Actions/CalendarTools/CalendarProfile) mail file owner set so that it doesn't match your user name, mail will be sent from that person specified in that field. The mail will also say it is really sent by you though. You will also see error messages in the Notes log ("SchedMgr: Error processing calendar profile document") if you rename a user but do not change their calendar profile.


IBM Redbooks

IBM redbooks are documents written by technical specialists within IBM. The quality of the technical information is generally very good. This is a list of the available publications related to Notes:

* Developing Applications with Lotus Notes Release 4, IBM form number SG24-4618-00
* LotusScript for Visual Basic Programmers, IBM form number SG24-4856-00, Lotus part number 12498
* Secrets to Running Lotus Notes: The Decisions No One Tells You How to Make, IBM form number SG24-4875-00, Lotus part number AA0424
* Lotus Notes Release 4 in a Multiplatform Environment, IBM form number SG24-4649-00
* IBM PC Server and Lotus Notes Integration Guide, IBM form number SG24-4857-00
* Lotus Notes on AIX Systems Installation: Customization and Administration, IBM form number SG24-4694-00
* Using ADSM to Back Up Lotus Notes, IBM form number SG24-4534-00

You can order these redbooks from the Redbook Web Site.


Helpful Non-Notes Books

You can order any of these books from Amazon Books, who will give you a 20% discount on them. All you have to do is click on the ISBN number of the book in the tables below.

Search Amazon for more books:

Title
Author
Publisher

ISBN
Reviews

Enterprise.Com
Jeff Papows Perseus Books 0738200646 Ken Yee
Javascript : The Definitive Guide David Flanagan O'Reilly & Associates 1565923928
Java Servlet Programming Jason Hunter, William Crawford, Paula Ferguson O'Reilly & Associates 156592391X
Dynamic HTML : The Definitive Reference Danny Goodman O'Reilly & Associates 1565924940


Reviews are still needed.

If you've read a good Notes book lately, [email] let the FAQ maintainer know how you liked it.


Books for Notes 4.x

You can order any of these books from Amazon Books, who will give you a 20% discount on them. All you have to do is click on the ISBN number of the book in the tables below.

Search Amazon for more books:

Title
Author
Publisher
ISBN
Reviews

10 Minute Guide to Lotus Notes 4
Sue Plumley QUE 1567615821
60 Minute Guide to Lotusscript 3 Programming for Lotus Notes 4 Robert Beyer
1568847793
Easy Lotus Notes Release 4.0 Elaine Marmel
078970756X
Foundations of Lotus Notes 4 Application Development Erica Kerwein, Sally Blanning Dejean
1568843453
How to Plan, Develop and Implement Lotus Notes in Your Organization : Covers Version 4.0 Michael Falkner
0471191078
Lotus Notes 4 Administrator's Survival Guide Andrew Dahl
0672308444
Lotus Notes 4 Plain & Simple Rupert Clayton
078211895X
Lotus Notes 4 Unleashed Randall A. Tamura Sams 0672309068
Lotus Notes Release 4 for Dummies Stephen Londergan
1568849346
Lotus Notes Release 4 for Dummies Quick Reference Stephen Londergan, Pat Freeland
0764500120
Mastering Lotus Notes 4 Kenyon Brown
0782117880
PC Learning Labs Teaches Lotus Notes Release 4 Charles Blum
1562763776
PC Week Guide to Lotus Notes Release 4 Eric Mann, Gerry Litton
1562763784
Teach Yourself...Lotus Notes 4 Bill Kreisle
1558284176
Using Lotus Notes 4 Cate Richards QUE 0789703688
Wiring the Workgroup : With Lotus Notes 4.0 Richard H. Baker
0070057257
Building Intranets With Lotus Notes 4.0 Steve Krantz Maximum Press 1885068107
Lotus Notes R.4 : Mastering Application Development Jonathan MacKenzie International Thomson Computer Press 1850322899
Integrating Lotus Notes With the Internet Steve Londergan
1558515046
Intranets Vs. Lotus Notes
Joseph T. Sinclair, David B. Smith, David Hale
AP Professional 0126455406
Using Lotus Notes As an Intranet Mike Falkner
047117548X
Lotus Notes : An Introduction to Programming Tony Pompii, John Jelliwell Prentice Hall Computer Books 0131507230
Lotus Notes Developer's Guide Rose Kelleher Wordware Publishing 1556225458
ABCs of Lotus Notes 4.X Rupert Clayton Sybex 0782120857
Network Design for Lotus Notes and Domino John Lamb, Peter Lew McGraw-Hill 0079132413
Teach Yourself Lotus Notes in 24 Hours Don Child Sams 0672311267
Lotus Notes Certification; Application Development and System Administration, with CDROM Scott L. Thomas, Amy E. Peasley McGraw-Hill 0079136745 Ken Yee
Lotus Notes Fat FAQs Ken Yee McGraw-Hill 007913680X Note: This book is late :-(
Building Intranets Lotus Go and Domino Michael Baryla Itp - Media 1850328978
Inside LotusScript Joe McGinn Manning 1884777481
CLP Training Guide: Lotus Notes System Administration & Application
Development
Tom Papagiannopoulos, Cathy Bannon, Dennis Maione New Riders 0789715058
Lotus Notes X Administrator's Guide Bret Swedeen Sybex 0782121837
Lotus Notes X, No Experience Required Rupert Clayton Sybex 0782121845
Mastering Lotus Notes X Kenyon Brown, Kyle Brown, Francois Koutchouk Sybex 0782121853
Building Intranets With Lotus Notes & Domino Steve Krantz, Eileen Rudden Maximum Press 1885068247
Lotus Notes Fast & Easy Richard Cravens Prima Publishing 0761513930
Lotus Domino Web Site Development Pete Wood, Steve Oliver McGraw-Hill 0079137555
Accelerated Lotus Notes Application Development Study Guide Libby Ingrassia Schwarz McGraw-Hill 007134569
Accelerated LotusScript Study Guide William Thompson McGraw-Hill 0071345612
Accelerated Lotus Notes System Administration Study Guide Libby Ingrassia Schwarz McGraw-Hill 071345620
Practical LotusScript Anthony Patton Manning 01884777767


Reviews are still needed.

If you've read a good Notes book lately, [email] let the FAQ maintainer know how you liked it.


Lotus Notes Magazines

The View, (800)810-1800 or (617)969-6666, $295/yr. Click [email] here to send a mail message to The View.

Lotus Notes & Domino Advisor, (800)336-6060 or (619)483-9851, $69/yr. Click [email] here to send a mail message to the Lotus Notes Advisor.

Lotus eBusiness Magazine (an on-line magazine)

Lotus Solutions Now! is a free publication on Lotus products published by Lotus.

Virtual Workgroups, (800)-227-1234, $40/yr. Not strictly a Notes magazine, but a good number of their articles describe how companies are using Notes.

netConnect, 011-44-171-221-7178, $225/yr for the printed version. This is a UK Groupware magazine with some articles on Lotus Notes. You can also [email] email them for additional info.

Group Computing, (415)348-0579, free to qualified individuals. This is a magazine that covers Notes and other groupware tools (including web based tools). [email] Drop them a note to see if you qualify.

Rupert's Lotus Business Week (Formerly Lotus eNews), free. A weekly email newsletter covering the business issues behind Lotus mail, groupware and web products. To subscribe, send email to [email] rupert.b@virgin.net.

Domino Power Magazine is a free monthly journal with weekly tips and daily Notes and Domino-related news.


Can you force a user to log in before using a database?

The normal way to do this is to set the database Default and Anonymous access to No Access.

With Domino 1.5b3 and later, add "&Login=1" to a Domino URL. This will force the user to log in before allowing access to a database (without requiring you to set Default and Anonymous access to No Access).


How do you replace the "No Documents Found" message in an empty view?

In the $$ViewTemplate, count the elements in the view using @Elements(@DbColumn). This will get the number of documents in the view. You can then use this in the paragraph hide-when for the embedded view to hide it. In another paragraph, you can use the opposite of this formula to unhide a custom message or passthrough HTML.


Does Domino support Hierarchical Names?

Yes, but they have to be used consistently in:
1) Person Documents' Username field
2) Databases' ACLs
3) Username/Password dialogs in the web browsers (the user has to type in the Hierarchical Name)


Is it possible to run a Domino server on a stand-alone PC?

Yes. You must have TCP/IP installed on the stand-alone PC; you should configure the loopback interface if you have no network card.
Configure the Domino server normally. When you run Netscape or MSIE locally, you can specify localhost, 127.0.0.1, or the system name like so: "http://localhost", "http://127.0.0.1", or "http://ntserver1" (assuming your stand-alone PC is named ntserver1).


How do you add a button that clears the fields in the form?

Add the following HTML code to your form:
<INPUT TYPE="reset" VALUE="Clear ALL">

If you want to control where this shows up, you can put the Submit button and this code in separate columns of a table with hidden borders.


What URL do you use to create a new document in a database?

The URL:

DatabaseName/FormName?OpenForm

can be used to create a document in a database. e.g., this will create a new document using the form "New Order" in the database orders.nsf in your Notes data directory:

orders.nsf/New+Order?OpenForm


How do you reopen a saved new document in read mode?

Add this to the $$Return field for the form:

  REM "By thomas@csshome.net";
  nsfpath := @ReplaceSubString(@SubSet(@DbName;-1); "\\"; "/");
  "[http://www.company.com/" + nsfpath + "/$DefaultView/" + @Text(@DocumentUniqueID) + "?OpenDocument]"


How do you use a different column as the hotspot to a document in a view?

Prepend "[ </a> ]" to the column formula for the first column. This will deactivate the hyperlink to the document. You can then reference the current document in any other column using the Domino syntax and @DocumentUniqueID as the document hyperlink.


Can you prevent the browser from prompting for a password when you use multiple web servers for your site?

You can add URL redirects so the browser thinks that it is accessing only one server:

www.server.com/ ->www.server.com/index.html
www.server.com/marketing ->www.dominoserver.com/marketing.nsf/$About
www.server.com/sales ->www.iisserver.com/sales/defaul.asp

In the example above, the browser always thinks it is accessing www.server.com.


How do you make parts of a document visible only to Web users or Notes users?

Use this formula to hide pieces of Notes documents if the current user is a Web client:

  @Contains(@UserRoles; "$$WebClient")

And this to hide if the current user is a Notes client:

  !@Contains(@UserRoles; "$$WebClient")


You can also use this to control when subforms are displayed. For example, you can have a "web footer" subform which you only want displayed when documents are shown on the web. In the design of the form for the documents, you would do a Create/InsertSubform with "Insert subform based on formula" and a formula of:

  @If(@IsMember("$$WebClient"; @UserRoles); "web footer"; "")

In Notes 4.6, there is a special text attribute you can set to hide parts of a document from web users or Notes 4.6 users.


Can Domino use directory links to reach databases?

The released version of Domino 1.5 can access DIR links by default, but betas acted the opposite way. To disable directory link support, put DominoNoDirLinks=1 in your NOTES.INI file. With this setting, Domino will limit web users from using dirlinks, but allows Notes clients and the Notes server to use the dirlinks.
If you do allow Domino to use DIR links, it will not use the ACLs specified in the .dir files so you should make sure the database ACLs are set up properly for the databases you put in the directory pointed to by the DIR link.


How do I refresh a page without losing information already entered?

Refreshing Keyword Fields
This is supported in Notes 4.6 if you turn on JavaScript support for the database.

Use $$Return
Save the document along with a "done" flag. If the document is not done and you want to refresh the document, you can use the $$Return field to reload the document in edit mode.

Use $$QuerySave Agent
Put this in a $$QuerySave Agent:

  Sub Initialize
    Dim s As New NotesSession
    Dim doc As NotesDocument
    Set doc=s.DocumentContext
    If doc.Done(0) = "No" Then
      Call doc.Save(True,False)
      Print "[http://domainname/databasename.nsf/viewname/"+doc.UniversalID+"?Editdocument]"
    Else
      Call doc.Save(True,False)
    End If
  End Sub

If the document is not marked as done, it will be reloaded in edit mode.


How do you add Java applets which have multiple class files?


Attach your classes in one document in your Notes database. In your passthrough HTML code that references the Java applet, set your codebase to that document :
<applet code=Clock1.class
codebase="/database.nsf/view/documentkey/$file/"
width=100% height=22 align=baseline>


How do you display the number of search results on a page?


You will have to use JavaScript to display the number of search result links:

""

You may have to substract a couple of links if you have other links on the page.


How do you reference view names with "/" and "\" in them?

Replace "\" with "%5C" and "/" with "%2F".


How do you remove the Domino footer from beta versions of Domino?

You can add "DOMINONF=1" to your notes.ini file, but you will risk forgetting that you are running a beta version that will expire soon. Released versions of Domino do not have this footer.


Can you put the action buttons for a view in a different frame?

Place 4 single pixel transparent GIFs at the top of a $$ViewTemplateDefault or $$ViewTemplate form, and make them hotspots. In each of the hotspot formulas, respectively, place the following:

  @DbCommand("Domino"; "ViewPreviousPage")
  @DbCommand("Domino"; "ViewNextPage")
  @Command([ViewExpandAll])
  @Command([ViewCollapseAll])

The order in which you place your hotspots is important, because they are accessed by the order in which they appear on the browser.
Add the following JavaScript to a $$HTMLHead field in the menu frame ("View" is the name of the frame where the view appears):

<SCRIPT LANGUAGE="JavaScript">
<!--
function Navigate(linkto)
{
  parent.View.location.href=parent.View.document.links[linkto].href
}
//-->
</SCRIPT>

Add the following HTML to your menu body (replace the images with whatever you want to use for your navigation icons):

<A HREF="javascript: Navigate(0)"><IMG SRC="/prev.gif" WIDTH=14 HEIGHT=11 BORDER=0 ALT=""></A>
<A HREF="javascript: Navigate(1)"><IMG SRC="/next.gif" WIDTH=14 HEIGHT=11 BORDER=0 ALT=""></A>
<A HREF="javascript: Navigate(2)"><IMG SRC="/exp.gif" WIDTH=14 HEIGHT=11 BORDER=0 ALT=""></A>
<A HREF="javascript: Navigate(3)"><IMG SRC="/col.gif" WIDTH=14 HEIGHT=11 BORDER=0 ALT=""></A>

This solution requires the use of a browser that supports JavaScript.


Can you do a Query by Form?

Create a form named "Search Form" with simple text fields that will be used to refer to the Notes fields of the documents in the "Search View" below. Name these fields form_Field1 and form_Field2 which correspond to Notes fields named Field1 and Field2. Add a field named "SaveOptions" with a default value of "0" (with the quotes) so the form is not saved when submitted.

Put a $$Return field that is computed for display at the very top of your search form with a formula of:

  tField1 := @Trim(form_Field1);
  tField2 := @Trim(form_Field2);
  a := @If (tField1 = ""; ""; "([Field1] = " + tField1 + ")");
  b := @If(tField2 = ""; ""; "([Field2] = " + tField2 + ")");
  SearchFields := @Implode(@Trim(a:b); " AND ");
  REM " *** Empty search will return everything ***";
  SearchString := @If(SearchFields = ""; "*"; SearchFields );
  db := @Subset(@DbName; -1);
  view := "Search View";
  REM "*** Replace spaces with '+'s ***";
  SearchView := @Implode(@Explode(view; " "); "+");
  @Return("[/" + db + "/" + SearchView + "?SearchView&Query=" + SearchString + "]")

To initiate a search, provide a link somewhere that with Action hotspot of

  @Command([Compose]; "Search Form");


Can you set Notes fields from JavaScript?

On the browser the Notes fields are rendered as objects associated with the form and are accessible via JavaScript. E.g. document.forms[0].NotesField.value = "hello" would set a notes text field named "NotesField" to the value "hello".
RichText, checkboxes and radio buttons are handled as array objects, so they must be indexed (e.g. NotesField[0]). You set different properties based on the field type ( .value=, .text=, .selected=true, etc.).


How do you use a URL to reference a specific document in a view?

Create a view with the first column set to the document name. This document name can be numerical, but precede it with a non-numeric character; otherwise, Domino thinks that you are trying to reference a Notes Document ID. You can then reference the document with the URL of:

db.nsf/DocView/DocName

where DocView is the view name and DocName is the document name in the first column.


How do you use transparent GIFs for web navigators?

1) Add the transparent GIF file to your database as described in the FAQ so it can referenced by the web browser.
2) Paste the same GIF into the Notes navigator.
3) Place the navigator in your web document as you normally would.
4) Use the web browser to look at the HTML source that Domino generated. Copy this HTML code and use in-line HTML to place this code into your document where you referenced the Notes navigator.
5) Replace the IMG SRC statement in the HTML with a reference to the transparent GIF.

If you use a computed field to generate the HTML code, you can make the HTML code independent of the database name by using a technique described in the FAQ.


How do you pass parameters to OpenAgent?

This code will create variables for each parameter you pass to ?OpenAgent. Values for each variable will also be set:

' From Kevin Pauli (kcpauli@usa.net), Technical Directions
Dim session As New NotesSession
Set doc=session.DocumentContext
Dim data List As String
args=doc.Query_String(0)
a = Instr(args, "&" )
Do While a>0
  args = Mid(args, a+1)
  a=Instr(args,"=")
  If a>0 Then varname = Left(args,a-1) Else Exit Do
  args=Mid(args, a+1)
  a=Instr(args,"&")
  If a>0 Then value = Left(args, a-1) Else value=args
  data(varname)=value
Loop

Can you have Domino search a specific view instead of a database?

Use this Domino reference:

db.nsf/viewname?SearchView

You can also use
db.nsf/viewname?SearchView&query=word

to specify a specific search word or words (replace spaces with '+').


How do you target a frame panel from a Navigator?

Assuming your web page has a frame defined with:

<FRAMESET COLS="15%,85%">
<FRAME SRC="/db.nsf/Nav1?OpenNavigator" 
MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO NAME="top">
<FRAME SRC="/db.nsf/By+Category?OpenView"
MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=YES NAME="bottom">
</FRAMESET>
<NOFRAME>
You need a browser that supports frames.
</NOFRAME>

Name your navigator:

Nav1  | Nav1


How do you delete the current document?

The easiest way to do this is to call this agent via ?OpenAgent from the current document:

Sub Initialize
  Dim s As New notessession
  Dim db As notesdatabase
  Dim rdoc, doc As notesdocument
  Dim uid  As String
  Dim returnto As String
   ' Get current document
  Set rdoc = s.DocumentContext
  Set db = rdoc.ParentDatabase
  returnto$=Left(rdoc.http_referer(0),Instr(rdoc.http_referer(0),"?")-33)
  uid$=Right(Left(rdoc.http_referer(0),Instr(rdoc.http_referer(0),"?")-1),32)
  Set  doc=db.GetDocumentByunID(uid$)
   ' Get the parent document so that you can bounce the user back to it after the deletion
  returnto$= Left(returnto$,Instr(Strconv(returnto$,2),".nsf/")+3)+"/all/"+doc.parentdocumentunid+"?Opendocument"
  Call doc.remove(True)
  Print "["+returnto$+"]"
End Sub


Can you target a frame using @URLOpen?

Yes, use this syntax (thanks to [email] Torben for this neat trick):

  @urlopen("http://www.company.com\" target=\"frame1")

where frame1 is the frame you want to open the URL into. You can use this @URLOpen syntax in your navigator hotspots.


How do you validate and jump to fields which have validation errors?

This example will check that all required fields are filled in. If a field is not filled in, it will move the cursor in the web browser to that field.

Put this in the onClick JavaScript event of your submit button:

javascript:DocumentSave();

Place in Form

function DocumentSave()  {
  fieldList = new MakeArray(2);  //set array for how many fields to check
  fieldList[1] = document.forms[0].f_ORG_UnitName;
  fieldList[2] = document.forms[0].f_ORG_UnitAbbreviation;
  DocumentOK = FieldValidation(fieldList);
  if (DocumentOK)
    document.forms[0].submit();
}

Place in Subform (Generic Sub-form)

// By James Fox@Com Tech
//==========================================================
//This function will return the length of an array
//==========================================================
function ArrayLength(obj) {
  var result = -1;
  for (var i in obj)
    result += 1;
  return result;
}

//==========================================================
//This function will perform field validation on the current Lotus Notes document
// for all fields in the fieldsToCheck array.
//==========================================================
function FieldValidation(fieldsToCheck){
  var continueFlag = true;
  for (var i=1; i <= ArrayLength(fieldsToCheck);i++) { 
    if (fieldsToCheck[i].value == "") {
      alert("Please ensure you enter a value for all fields marked with a Star.");
      continueFlag = false;
      fieldsToCheck[i].focus();
      break;   
    }   
  }
  if (continueFlag) 
    return true;  
}


How do you prevent people from deleting file attachments?

At the bottom of your document, pass the HTML tag "<NOSCRIPT>". This will hide the attachments from the browser. However, this can cause problems if you are displaying databases with the Use JavaScript option enabled.

If you are using Domino/Notes 4.6 and later, add a field named "$V2AttachmentOptions" with the value "0" to hide the attachments from web users.


How do you remove the Domino-generated Navigation Bar from Views?

Use a view template as described in the Domino documentation.


Can you store transparent and animated GIF's in the Notes database for a site?

This was a useful technique in Internotes Web Publisher and TILE. You would store all the special GIF and JPEG files as attachments in the Using document for a database. When the web site was generated, these files would then be detached and placed in the same directory. This way, there is only one copy of these images which you'd reference in custom HTML for the site for generating backgrounds, etc.

Ideally, Notes would have something like a graphics link or file attachment link, but it doesn't. However, what you can do is use a URL to reference the file attachment where it lies:
Look up the Document ID for the document where you are storing your images
For the URL in your custom HTML code, use the database path, then the Document ID followed by /$file/filename.ext?OpenElement

Limitations are that:
The document can't be the About or Using documents
The URL can be broken if you delete the carrier document, so only generate the carrier document once
The URL will be broken if you are making a copy of the database instead of replicating


If you don't want the long Notes Document ID to be visible to your users, you can also do the following:
Create a blank database called webfiles.nsf.
Create a form called Web Files. On it, place an editable text field called Name, and a rich text field called Attachment.
Create a view called Files. Make the first column sorted with a formula of Name.
Compose a Web Files document. In the Name section, write "GIFanims". Attach the file (e.g. named animation.gif) in the attachments field.
The URL for this attachment: /webfiles.nsf/Files/GIFanims/$file/animation.gif.


How do you work around Domino's keyword field deficiencies?

Saved documents automatically select the first value of a keyword field even if the user hasn't selected one.
For the keyword formula, use:
"--Select from list--" : @DbColumn() so that blank is selected when nothing is selected
You can then check for the first value using a field validation formula to force the user to select something.

You can't have "Allow values not in list" for a keyword field.
Use two fields, one called Category which is made from the @DbColumn, and a separate text field called OtherCategory. You can then have a computed field named RealCategory which is equal to OtherCategory if it is non-empty or Category if it is empty.


How do you decode parameters in URLs?

Using these two functions, you can decode parameters into an array of strings that you can later parse. These two functions handle parameter characters such as spaces which had to be "escaped" to be passed as parameters.

Function unescape( thing$ ) As String

     ' From Hugh Pyle@NIP
     ' Treat thing$ as a string which came from a Web URL;
     ' un-escape it, ie: "+" becomes space, and %HH become individual characters.
     '
     Dim a$
     Dim bit$
     Dim j%
     Const hx$ = "ABCDEFabcdef1234567890"
     For j=1 To Len( thing$ )
          bit$ = Mid$( thing, j, 1 )
          If bit$="+" Then
               bit$ = " "
          Elseif bit$="%" Then
               If ( Instr( hx$, Mid$( thing, j+1, 1 ) )>0 And Instr( hx$, Mid$( thing, j+2, 1 ) )>0 ) Then
                    bit$ = Chr$( Val( "&H" & Mid$( thing, j+1, 2 ) ) )
                    j = j + 2
               End If
          End If
          a$ = a$ + bit$
     Next
     unescape = a
End Function


Function URLGetParamArray( url$, param$ ) As Variant
     ' From Hugh Pyle@NIP
     ' Find as many occurrences of "&param=" as appear in the URL, and return the value(s) as an array.
     ' Unescape the values while we're doing it.
     Dim n%, m%, c%
     Dim p As Variant
     c = 0
     Redim p( c ) As String
     n = Instr( 1, url$, "&" + param$ + "=", 5 )
     While n>0
          Redim Preserve p(c) As String
          m = Instr( n+1, url$+"&", "&")
          p(c) = unescape( Mid$( url$, n+ Len(param$) + 2, m - n - Len(param$) - 2) )
          n = Instr( m, url$, "&" + param$ + "=", 5 )
          c = c + 1
     Wend
     URLGetParamArray = p
End Function

Can you create field help on a web browser?

Yes, put this into the HTML attributes for the field:

onFocus="window.status='Please enter a subject'" onBlur="window.status=''

This only works on JavaScript-enabled browsers such as Netscape and MSIE.


How do you put HTML code before the tag?

This is needed for setting up frames within a Notes database because the HTML <FRAMESET> directive must precede the <BODY> tag.

Create a new form called HTML with the first field named "HTML". You must call the field "HTML"; if you do not, Domino will put a <BODY> tag in front of everything in the HTML for the page automatically. This will let you code raw HTML and leave it in a Notes database instead of needing standalone HTML pages just to do frames.

In Domino 1.05 and above, you can also use the $$HTMLHead field to store code that should go within the <HEAD> tag.


How do you improve performance to web clients?

1. Shared fields and subforms slow down the server. Try not to use too many shared fields.

2. DbLookups are cached in the Notes client but not in the Domino server. If you are doing the same DbLookup multiple times, create a computed-for-display field to hold the initial lookup and reference that lookup in other fields that would have done DbLookups.


How do you remove Domino's default submit button?

Create a button hotspot on the form. On a separate line above it , put "<!--" and add a line below it with "//-->" using the HTML paragraph style. This will comment out the Domino button on the browser.

Another way to get rid of the Domino Submit button is to create a hotspot button on the form but do not assign a name or any code to it. It will not appear when you compose the document from a browser.

And for your amusement and all the other variations on this, check out the
How To Hide A Submit Button web site :-)


Can you display a text field as a TEXTAREA?

From Howard Katz (HKatz@FocusedManagement.com):

Simply code your text field as "Allow multi-values", then on the Options tab, check "New line" for "Separate values when user enters" and "Display separate values with". This plain text field will then be displayed as a TEXTAREA. You can set the HTML attributes of the field to adjust the size of the TEXTAREA.


How do you prevent web users from being able to browse your database directory?

Here is the undocumented feature (it will be a settable option in Notes 4.5) which will prevent Web clients from seeing a list of all the databases on a Notes/Domino server.
Note: If they can guess the directory and filename of a particular database, they can still get to the database. Remember to use ACLs or dirlinks to really prevent access to non-public databases.

On the HTTP settings subform (used in the Server\Server form in the NAB), add this field: "HTTP_DatabaseBrowsing"
Make it a keyword text field, editable.
For the keywords, specify "Allow|1" and "Not Allow|0".
Open the server document for the Domino server, set the field to the appropriate value, and save the doc.
Shut down and restart the HTTP/Domino task to get Domino to recognize the new setting.


Can you do banner ads with Domino?

This technique works well if your site is done in a Notes database (it won't work w/ static HTML files that are served by Domino):
1. Create a database for your ads.
2. In the database's ad view, create the HTML for the image, text, and hyperlink.
3. In each document you want to put an ad on, use a @DbLookup with an @Random to select one of the items from the view.
4. Use passthrough HTML using "[" and "]" to pass the HTML through.

You can also put readernames fields on the ad documents so authenticated users get appropriate ads that are matched to their profiles.


How do you detach a file submitted by a web browser?

The attachment comes in as a Notes V2 attachment. The following code would extract the attachment into a file named "file.web":

  Dim Item as NotesItem
  Dim Object as NotesEmbeddedObject
  Dim Doc as NotesDocument
  Set Item = Doc.GetFirstItem("$FILE")
  Dim ItemName As String
  ItemName = Item.Values(0)
  Set Object = Doc.GetAttachment(ItemName)
  Call Object.ExtractFile("file.web")

If you need to extract multiple items:

  Forall Item In Doc.Items
    If (Item.Name = "$FILE") Then
      ' Process one item
    End If
  End Forall

If you need to check whether any of these are in a Rich Text field, use the NotesRichTextItem's GetEmbeddedObject method or look in the EmbeddedObjects property of the NotesRichTextItem.


How do you make user registration immediate?

There are several ways to do this. These techniques involve updating the index of the appropriate NAB which contains the newly registered users:

Open the Person Document View in the Browser
When you register a new Person document in the NAB, change the $$return variable to open the new person document with this:

  "[/names.nsf/($users)/" + @ReplaceSubString(fullname; " "; "+") + "]"

This will cause the index of that view to be updated so that the next username look up will work.

Run the updall Program
In the Terminate Event of the registration form, you can add the following LotusScript:

  Dim progname As String
  progname = "d:\notes\nupdall names.nsf"
  taskID = Shell (progname, SHELL_MAX_FOCUS)

You will have to adjust the updall name and path as appropriate for your system.

Do a View Lookup with the Notes API
Add this to your Declarations section:

  ' NAMELookup and OSMemFree are used in EnsureUserInNAB.
  ' NOTE: if you are running this app on a platform other than
  ' Windows 32 Intel, then you will have to change the name of the
  ' dll in these two declarations. Look in your Notes executable
  ' directory for *notes.dll to see what it is called, or for the proper
  ' form of shared library on your platform.

  Declare Sub NAMELookup Lib "nnotes.dll" _
  (Byval serverName As Integer, _
   Byval flags As Integer, _
   Byval numNameSpaces As Integer, _
   Byval nameSpaces As String, _
   Byval numNames As Integer, _
   Byval names As String, _
   Byval numItems As Integer, _
   Byval items As String, _
   rethBuffer As Long _
  )

  Declare Sub OSMemFree Lib "nnotes.dll" (Byval hBuffer As Long)

Now create a new sub:

  ' This sub is used to guarantee that the NAB view of users is up-to-date
after adding a new
  ' user. Domino 1.5 does not force the view to be up-to-date when
authenticating users, so
  ' we'll do it ourselves so the user can start working right away.

  Sub EnsureUserInNAB(Byval fullname As String)
    Dim hBuf As Long 
    Call NAMELookup(0, 0, 1, "$Users", 1, fullname, 1, "HTTPPassword", hBuf)
    Call OSMemFree(hBuf)
  End Sub

Then, once you have modified all of the documents in the NAB you are going to modify, call EnsureUserInNAB with the user's full name. The NAB will be up-to-date.
This technique is used in Lotus' Domino Registration sample.


How do you refer to CGI variables in a $$Query*Agent?

If you'd like to operate on a CGI variable in your agent, you must include a text field that is named the same as the CGI variable on your form. You can then use "Session.DocumentContext" in your $$QueryOpenAgent or $$QuerySaveAgent to access the CGI variable like so:

  Dim session As New NotesSession
  Dim context As NotesDocument
  Set context = session.DocumentContext
  Print "HTTP_User_Agent = " & context.HTTP_User_Agent(0)

This will display the web browser being used.


How do you delete a document by the UNID?

If you are using a $$QuerySaveAgent you can get the unid from the NotesSession.DocumentContext.UniversalID.
If you are running an agent with ?OpenAgent, append &UNID=docid to the end of the URL, where docid is either on the document that you are working with, or, is computed by Domino with @DocumentUniqueID and use the following as the delete agent:

Dim s As New NotesSession
Dim db As NotesDatabase
Dim tempdoc As NotesDocument
Dim realdoc As NotesDocument
Dim RealUNID As String
Dim readerlist As NotesItem
Dim templist As NotesItem

Set tempdoc = s.DocumentContext
Set db = s.CurrentDatabase
RealUNID$ = Right$(tempdoc.QUERY_STRING(0),32)
Set realdoc = db.GetDocumentByUNID(RealUNID$)

Call realdoc.remove(True)


How do you set up a field to autowrap when text is typed in a browser?

Add the HTML tag "WRAP=Virtual" in the help description of the rich text field.

You can also use the tags COLS="xx" and ROWS="yy" to set the width and height of the field.

For Notes 4.6 and above, put these tags in the HTML attributes for the field.


How would you secure a Domino server?

This is what KEY Enterprise Solutions normally recommends for its clients:

* Put the Domino server in a separate organization in case some of your databases have */org in the ACL, then cross certify the Domino server with internal servers
* Put a password on the Notes server ID in case someone manages to steal it off your site
* Encrypt all databases w/ the Notes server ID in case someone manages to steal your databases
* Set all databases to enforce local security in case someone manages to get the database and the server ID
* Turn off database browsing for web clients so people can't reach databases you didn't mean to publish
* Set all databases to Default No Access so only validated people can get into databases
* Activate SSL (whether self-certified or Verisign) to secure your network traffic to web clients
* Turn on network encryption when Notes clients talk to the Domino server over the Internet
* Protect all views you don't want accessed because web users can use the 3PaneUI parameter to see all your database views.
* If you are using the Domino server as a Notes server, put files you don't want Web users to access in a directory with a DirLink and disable Domino's DirLink support to allow Notes users to use the DirLinks but not Web users.

Also from GroupAware:
* Name your databases and URL's carefully. If users manage to go over hidden link or manage to browse your system, they may be able to guess what you are planning from URL names.


How do you prevent people from submitting a form multiple times?

By using a META tag, you can set the page to expire on a date that has already passed, and use the Pragma parameter to tell the browser not to cache the file. This will prevent the user from hitting the Back button on the browser and resubmitting the page multiple times. Put this code into the $$HTMLHead field:

"<META HTTP-EQUIV=\"expires\" content=\"Wednesday, 27-Dec-95 05:29:10 GMT\"><META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"


How do you add a Javascript button which validates the form and then submits it?

Your checkForm function should have the code to validate as well as submit. Your button should be of the type "button" and not submit. If the validation fails make an early exit from the function.

Add the following code in the $$HTMLHead field:

"<SCRIPT LANGUAGE=\"JavaScript\"> 
function checkForm() {
  if (document.forms[0].Name.Value == \"\") {
      alert(\"You must enter your name\");
      return false;
  }
  document.forms[0].submit();
  return true;
}
</script>"

Add this code for a submit button as passthrough HTML or with the HTML style:

  <INPUT TYPE="Button" VALUE="Submit" onClick="checkForm(0)">

Now that you've added a special button, you'll have to remove the default one that Domino generates via the FAQ on how to remove the submit button.


How do you give a Value= tag to a field?

Add "| valueToReturn" after the elements in your keyword list.


How do you set a Cookie?

This is an example which you can place in a $$HTMLHead field:

"<META HTTP-EQUIV=\"SET-COOKIE\" CONTENT=\"cookiename=" + Cookievalue +"; path=/;
expires=Thu, 01-Jan-2009 12:00:00 GMT\">"


How do you make a field look like a password field?

If you put <INPUT TYPE=password> in the Help description of a field, the characters your user enters will be masked by the "*" character.

In Notes 4.6 and above, add "TYPE=password" to the HTML attributes of the field.


When do you have to pay for Client Access Licenses (CALs)?

This is a really confusing topic, even if you try to look up what it means to Microsoft IIS or Netscape or Groupwise. This is how I understand it (have a lawyer review Lotus' CAL documentation if you need to confirm):

The web CAL is only for direct intranet/extranet users, i.e. users who have a very close relationship with your company. Examples would be your company inventory app that distributors use to collaborate w/ you. Another example is if your employees acces their HR records over the web.

For Internet users who are logging in to participate in discussion forums on your site, there is no charge because they are not directly related to your company.

Note that most people think IIS is free. IIS itself is free, but usually you need a back end database since IIS does not have a built-in DB; this is where Microsoft gets you to pay more for buying and using SQL Server. For RDBMS CALs, the only way to get around them is to use one RDBMS login for everything and then use appropriate SELECT statements to mask data for each user. Once you start adding real DB username/passwords, you are also subject to CALs for the RDBMS. Note that you will be able to use this same technique in Notes R5 since it supports sessions.

Note: apparently, the CAL policy was changed sometime in March, 1999. The above description applies to CALs from last year. The current CAL policy as written seems to say that you need a CAL for any authenticated user (even if not an employee or distributor) unless you want to spend $25K on a Server Access License. This is patently stupid. This FAQ will be rewritten as soon as I can figure out what the new policy really means. Sorry for any confusion the previous FAQ may have caused. The direct link to Lotus' CAL information is http://www.lotus.com/dominocal.


What @Command do you use to delete the current document?
@Command([EditClear])

Can you automatically expand sections in documents?

You can use the ExpandSection argument after OpenDocument in a URL as follows:

  ...?OpenDocument&ExpandSection=1,3

This will expand the first and third section in the referenced document.


Can you change the Twistie graphics in Notes Views?

In the Icons directory for Domino, e.g., c:\notes\data\domino\icons, you will find the files expand.gif and collapse.gif. These are the GIFs used for the twisties displayed in Notes views for the web. Note that you will change the twisties for all views displayed on the web by changing these two files.


Are @PostedCommands Supported?

Domino treats @Commands and @PostedCommands the same way.


Can you put a background bitmap in the About document?

Not directly using Notes 4.5. You should be launching the first doclink in the About document instead and linking to a document where you can set the background.

However, if you are willing to put in raw HTML at the top of the document, you can add a <BODY BACKGROUND="bg.gif"> tag at the top of the file by formatting the paragraph with the HTML style or using passthrough HTML.


How do you access fields on a Parent document from an unsaved response doc?

Create a computed for display field named QUERY_STRING on your form with the formula "". You can then access any fields from the parent using this in a second, computed field:

  parent := @Word(@Right(@Uppercase(QUERY_STRING);"&ParentUNID=");"&";1);
  valueNow := @GetDocField(parent; "Field1");


Why do you need Author access to do a search on a database?

When do a search from the web, you actually author a document (though the Save Options are set to '0'); you need the access rights to create the document. This is why anonymous users can't search a database where you have set Default and Anonymous access rights to No Access. There are several workarounds:

1) Allow Default and/or Anonymous to have Author access, but change the Form Properties on each form so that users with specific Roles can create the normal forms in the database.

2) Create a Search Site database where the default access is Author. You can run searches from this database without compromising the security on other databases.

3) Give Default access the ability to create Public Access documents. Then, set your Search Form so it is available to Public Access Users.

4) Hand code the query URL as suggested by Torben Moelgaard:
What actually happens when you fill out the web-form, is that a url like this is built by the browser:

  www.corp.com/db/view?searchview&query=apple+and+pie

And Domino then accepts that request and makes the search.
a. Create a form called Search.
b. Since you'll use the ?readform parameter to open the form Domino won't produce <form>...<input type=text/submit/etc> </form> tags, so you'll have to make those yourself.
c. Create an HTML input field called Input
<input type=text name=Input>

d. Make your own submit button with this code:
<input type=button onClick="location.href='http://www.corp.com/db.nsf/$defaultview?searchview&query=' +  document.forms[0].Input.value">

When you call it with http://.../db/Search?readform it will allow searhing with only reader-access.

You can also disable a return from submitting the form by adding the following passthrough HTML (thanks for this tip go to Kevin Pauli):

  <form onSubmit="return(false)"> ... </form>


Can you make a link that lets the user jump back two web pages?

There are two methods of doing this. You can use Javascript passthru HTML:

<SCRIPT language=javaScript>
  history.go(-2)
</SCRIPT>

Or you can use hidden HTML input fields:

On the first form, place a computed for display field named http_referer in the first form. Place another formula on this form named CreateBackStash with a formula of:

"["+"<input type=hidden name=BackStash value=\""+http_referer+"\">]"

On the second form, place an editable field called BackStash, but make this field hidden in Notes. In the $$Return field of this form, use BackStash as the URL you want to return to.


Can Domino forms be mail-enabled?

Yes. Make sure all the mail fields are set (To, etc.) in the form. Then in Form Properties, select the On Close Present Mail Dialog option. When Domino saves the form, it will mail the document.


Can you have a single URL that opens the user's mailbox?

This is from Ron Heller (hellerr@msnotes.wustl.edu):

Create a database that everyone connects to (let's call it getmail.nsf). Set the ACL -Default- and Anonymous to No Access, with all your users given Reader access (you can do this with a group or wildcard OUs) - so they must be authenticated when they hit the URL.

Set the Database Properties to "launch the designated doclink", which is a blank document (the only doc in the db) created with a form as follows:

Place a hidden Computed for Display field at the top with the name $$HTMLHead and give it the following formula (note that the column names are from the R4.5 mail template and may change in other templates):

mailFile := @If(
  @IsNotMember("$$WebClient"; @UserRoles);
  "";
  @ReplaceSubstring(@DbLookup("":"NoCache"; "":"names.nsf"; "($VIMPeople)"; @Name([Abbreviate]; @UserName); "MailFile"); "\\"; "/")
);
URL := @If(
  mailFile = "";
  "";
  @IsError(@UserAccess("" : mailFile));
  "";
  "/" + mailFile +
    @If(
      @Right(@LowerCase(mailFile); 4) = ".nsf";
      "";
      ".nsf") +
    @If(
      @IsError(@DbColumn(""; "" : mailFile; "($HeadlinesView)"; 1));
      "/$Inbox/?OpenView&Count=30&ResortDescending=2";
      "?OpenDatabase"
    )
);
@If(URL = "";
  "";
  "<TITLE>Web Mail Connect</TITLE><META HTTP-EQUIV=\"Refresh\" CONTENT=\"1;URL=" + URL + " \">"
)

Place a second, visible Computed for Display field on the form with this formula:
@If(
$$HTMLHead= "";
"Sorry: Mail file not found on this server.";
"Connecting to Mail File for " + @Name([CN]; @UserName) + @Repeat("."; 25))

When a user enters the URL http://myserver.xxx/getmail.nsf, they are prompted for UserName and Password and sent directly to their Inbox, sorted descending.


Another method using a button comes from Bill_Gordon@mgic.com:

1. Create a form anywhere and place a button on a form called My Mail with @Command([FileSave]) for the formula. Set the security to force login when accessing this document's URL or use &Login.

2. Place a hidden computed field on the form called SaveOptions and set the formula to "0" (zero in quotes). When the form is submitted it will never create a document.

3. Place a hidden computed field called MailName on the form and set its formula to @V3UserName.

4. Create an agent that is called from the WebQuerySave event of the form. The agent performs a lookup to get the user's mail file name from the name and address book, formats a return URL and uses Print to send it back to the browser. See example below:
Set db = session.CurrentDatabase
Set nabdb = New NotesDatabase( db.Server, "names.nsf" )
Set doc=session.DocumentContext
strng = "Form = 'Person' & FullName = '" & doc.MailName(0) & "'"
Set collection = nabdb.Search ( strng, dateTime, 0)
If collection.count = 0 Then
address = "[" & "https://servername/database.nsf/viewname/WebError?OpenDocument" & "]"
Else
Set persondoc = collection.GetFirstDocument
address = "[[" & persondoc.MailFile(0) & ".nsf]]"
End If
Print address

5. An error form, WebError, was also created in the database. If the logged in user does not have a mail database the error form is displayed.


How do you pass variables into a form via URL's?

In a URL, you can add ampersands (&'s) followed by parameters you wish to pass into a form (e.g., "http://www.site.com/db.nsf/8A8BB01ADEB05120852564180068A3F4?OpenForm&param1=7&param2=key1")

In the receiving form, create a variable called query_string. This field will be initialized by Domino to everything following the question mark in the URL (in the example above, this would be "OpenForm&param1=7&param2=key1"). In the default value formula for the field you want to check this field in, parse the value of query_string (e.g., to get the last parameter, use "@subset(@explode(query_string;"&");-1) " to get "param2=key1"). You can then do anything you want with the parameter.


Why do I get SSL errors when using MSIE?

When using MS Internet Explorer running with High Security, it will refuse to connect to sites using self-certified SSL certificates. You have two options:
1) Purchase a Verisign server ID from Verisign.
2) Set all your MSIE clients to use Medium Security so you just get warnings.


Can you change the look of the search input form?

Create a form named $$SearchTemplateDefaultForm and Domino will use this for its search input template.


Can you have multiple navigators on one page?

Not if you are using navigator templates ("$$NavigatorTemplate for xx" forms); templates only support one navigator.

If you use a document, you can have multiple $$NavigatorBody fields in the document.


Can views be shown to web clients with the Notes V4 UI?

To make web browsers access Notes views with the Notes V4 "multi-pane look", add "&3PaneUI" to any of your ?OpenView commands. For example:

db.nsf?OpenDatabase&3PaneUI

will open the database using the multi-pane Notes V4 UI.

For Notes 4.6, you also have to add DominoEnable3PaneUI=1 to your notes.ini file.


Can you get rid of Domino's tags?

If you add "<!-- " to the end of the value of the $$HTMLHead field, and add "--></HEAD>" at the very top of the form, you'll effectively comment out the Domino-generated <BODY> tag by making it look like a comment in the <HEAD> section..

It ends up looking like this:

  <!-- </HEAD><BODY>
  --></HEAD>

thus leaving you free to add your own <BODY> tag.


How do you make a Domino site searchable by web search engines

Most web search engines like Excite or AltaVista so not follow links with "?" because they think those are CGI links; Notes 5 allows you to replace the "?" with "!". If you are not using Notes 5, you can do the following:

Create a view named "Pages" that selects all documents that you want searchable, and first sorted column of the view contain each documents key value named "Key". The "Key" value can be @Text(@DocumentUniqueID).

If this is a 4.6 view, use the "treat as HTML" feature. In one of the columns, set the formula to something like this:
"<a href=\"Pages/" + Key + "\"">Page " + Key + " from MySite.com</a>"
If it is 4.5, you'll need to create the same <a>..</a> tag in a column, and surround it with "[" and "]" to make it passthru HTML.

Submit this view (the url "http://server/path/database/Pages") to the web search engine. The engine will traverse the view, follow all the links, and index your pages. However, if the database contains 1000 documents, but the web server is only set to display 50 at a time in views, only the first 50 will get indexed.

Here's a better way to do this from Niels Harremoes (niels.u.harremoes@dk.pwcglobal.com): use an agent named e.g. GenLinks to print a page with links to all documents and then point the search engine to http://server/path/database.nsf/GenLinks

If you already have a view containing all the documents you want indexed, you could also just use that view. This also has the advantage of not cluttering your database with another view:

Sub Initialize
  Const viewname = "(CrawlIndex)" 'A view displaying all the documents to be indexed - use a view alias if needed
  Dim ses As New NotesSession
  Dim view As NotesView
  Set view = ses.CurrentDatabase.GetView(viewname)
  Dim d As NotesDocument
  Set d = view.GetFirstDocument
  While Not d Is Nothing
    Print {<A HREF="} & viewname & {/} & d.UniversalID & {">} & d.Title(0) & {</A><BR>} & Chr(13)
    Set d = view.GetNextDocument(d)
  Wend
End Sub

Of course, generating the links in this way is a lot less efficient than having Domino generate a view - however, since the agent will only be called by the search engine once upon visiting the site, this shouldn't be a problem.

Other things to be aware of: Text inside collapsed sections won't get indexed, since the search engine won't go click the "expand" link. Attachments won't get indexed either. A workaround for that would be to expand the agent above to generate links to all attachments as well as to the document itself.


How do you add context-sensitive help on Domino web pages?

You can using this bit of Javascript which you can put in your $$HTMLHead field:

<script language="javascript:>
function showHelp() {
  var helpURL = "/[dbPath]/www-help/[keyName]";
  helpWindow = windowOpener( helpURL,"helpWindow");
}
</script>

and somewhere later:

<input type=button value="Help" onClick="showHelp()" >

where [dbPath] is a computed for display field with the following:

  db1 := @Subset(@DbName; -1);
  db2 := @ReplaceSubstring(db1; " "; "+" );
  @ReplaceSubstring(db2; "\\"; "/" )

and keyName is a computed for display field that resolves to a document name in the help view.


What companies will host Domino web applications for a fee?

In the United States:
* Strategic Systems Consulting in Atlanta, GA
* Interliant in Houston, TX
* PSR Software in Orlando, FL
* Going On in Lombard, IL
* Prominic.NET in Urbana, IL
* RiverWatch in Fort Mitchell, KY

In other countries:
* Right Source in Germany
* .scon - Siekmann Consulting in Germany
* Business Interactive in Canada


How do you open the About This Database document with a URL?

Use @URLOpen("/db.nsf/$About").
Similiarly, you can use @URLOpen("/db.nsf/$Help") to open the Using This Database document from the web.


How do you select multiple documents in a view and run an action button on them?

In your view have a column which creates a check box for the document. A passthru column formula like:

<input type=\"checkbox\" name=\"noteids\" value=\"" + @Text(@NoteID) + "\">

Note that for every document in the view, the check box will have the same Name, ie., "noteids".

Now next step is a $$ViewTemplate for this view. Let it start with a <FORM> tag created using passthru HTML:

<FORM METHOD="POST" ACTION="ProcessNotes?CreateDocument">

This is followed by $$ViewBody and then (using passthru):

<INPUT TYPE="Submit" Name="Action" Value="Action1">
<INPUT TYPE="Submit" Name="Action" Value="Action2">

... etc...
</FORM>

When the view comes up on the browser, the user will see a form with multiple Submit buttons, each corresponding to a certain action to be done on the documents selected through the check boxes.

For the next part of this, you will need to have corresponding fields in a dummy Notes form called "ProcessNotes". A field named "noteids" (text, multivalue, editable) and another by name "Action" (text, editable) and of course a $$QuerySaveAgent. You will get the NoteID of all the checked documents as a multivalue list in "noteids" and the action chosen by the user as a value in "Action" when you get into your QSA. You can use this code to iterate through the document list:

ForAll NoteID in ContextDoc.noteids
  set Doc = Db.GetDocumentbyID(NoteID)
  ' Process the note..according to the value of ContextDoc.Action(0)
End ForAll


[<a name="NT000010F2">
How do you jump back to the current view from the current document?</a>]

You can use @ViewTitle to get the name of the current view and re-open it.
This is only needed if the document is in multiple views.


How do you handle field inheritance when composing from the Web?

In the URL, you must have a ParentUNID argument if you are generating your own URL links which use the OpenForm or CreateDocument commands. You also have to have the Inherit Fields Form Property activated.
An easier way to do this is to put @Command([Compose]; "<formname>") in an Action Hotspot where <formname> is the name of the form with inherited fields to compose.


Can you customize the "Deleted" message?

There is only support for this in Notes 4.6.
A workaround is to create a delete check box in the document and let the $$QuerySaveAgent do the work.


Does Domino support Server-Side Includes (SSI)?

Yes, but only for files with an extension of .shtml. If your files are named with an extension of .html or .htm, change the following line in your http.cnf file in your Notes data directory:

  imbeds on .shtml


Can you attach files to a document using a web browser?

This works only if the user is running Netscape Navigator. It will not work with Microsoft Internet Explore 3.0. This is not a deficiency in Domino; the original MSIE 3.0 and 3.01 don't support web uploads. MSIE 3.02 has a file upload add-on that does support uploads.

Create an action hotspot (Create/Action/ActionHotspot) on the form with a formula of @Command([EditInsertFileAttachment]). No field needs to be added; a field will be automatically generated by Domino after the hotspot. Domino will create a Notes V2 style attachment (attachment shows up at bottom of page after a horizontal rule) when the user does this.

In Notes 4.6 and above, you can create a FileUpload Web Element on the form. Unfortunately, Lotus didn't make 4.6 entirely backwards compatible with Notes 4.5. If you used the old file upload method and you have JavaScript generation enabled for the database in Notes 4.6, the old method doesn't work.


How do you create a framed page with a navigator in one frame?

Create a form called "Navigator" with this code at the top of the page:
<BASE TARGET="bottom">
and add a field named $$NavigatorBody that evaluates to the name of the navigator.

Add the frame with this code which will place the navigator at the top and a default view at the bottom:
<FRAMESET FRAMEBORDER=0 FRAMESPACING=0 ROWS="45,*">
<FRAME SRC="/db.nsf/Navigator/?OpenForm" MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO NAME="top">
<FRAME SRC="/db.nsf/By+Category?OpenView" MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO NAME="bottom">
</FRAMESET>
This HTML must go into a field named $$HTMLHead so that it is generated before the <body>; alternatively, you can make a single field named HTML in your form and place this code in it.


Flash Cards

Avalon Consulting makes a $60 Notes R4 database with flash cards for CLP's who are taking the update exams. They also plan to make a version for uncertified folks and a skills assessment tool for hiring managers. You can reach them via [email] email or (804)741-6547.


Computer Based Training

The following companies make Lotus Notes CBT courseware:
* Self Test Software (770) 971-8940
* Lotus (800)782-7876
* CBT Systems
* ReCor
* Professor 3T (end-user training)
* TLCC


Virtual Classes via the Internet

The Learning Continuum Company is the first company to offer this; they cover Notes, Domino, LotusScript, and JavaScript using Lotus' LearningSpace for Domino.

Others will offer courses based on Lotus' LearningSpace soon.


Lotus Education Helpline
The Lotus Education Helpline has an Exam Guide for Lotus Notes; the number is (800)346-6409. Lotus Fax Support also has sample exam questions at 617-253-9150.

Notes Utilities

[ftp] John Buckman's Lotus Notes Phone Dialer
[ftp] Alert! New Document Notifier
[ftp] NotesMon Server Crash Alert Monitor

Notes Related Programs or Information

* [ftp] The LNOTES-L Archive
* [ftp] OS/2 Netware Requester Software
* [ftp] Lotus Internet Cookbook (.NSF format)
* [ftp] Notes Database Templates from Lotus
* [ftp] Lotus Notes Mobile Survival Kit


How do I publish Notes databases as Web pages?
There are a few companies that make Lotus Notes to Web page conversion programs. These programs allow anyone who has a Notes database to publish equivalent Web pages with very little work.

Lotus Internotes Web Publisher (derived from the Corporate Software product below) The InterNotes development team also has their own Web site here which has previews of features in future versions of the Web Publisher and discussions among users. Lotus Notes V4 IWP has the ability to publish and take input from forms directly, but requires the Notes server to be run on the machine used as the web server. For Notes V4.5, Lotus will be including Domino as a web server built into Notes, but this will also require a machine running Notes for the web server.

The Shelby Group's T.I.L.E. (The original Notes document library is also available here.)

Corporate Software's Web Link

There is also a program called FormGate written as a CGI script that allows filled out Web forms to be submitted into a Notes database. Note that The Shelby Group's T.I.L.E. program also supports this functionality and has hired the author of FormGate, so the functionality of T.I.L.E.'s interface will be a superset of both eventually.

Dogwood Software has a product called Site Publisher which works w/ R5.


Where can I get a Web browser gateway for Notes?
The browser gateways present the familiar Lotus Notes interface for users wishing to access Web pages on the Internet. Unfortunately, there are limitations to how HTML maps to Notes documents (e.g., Notes doesn't have doclinks into the middle of a document).

[ftp] Chris Davey's Public Domain WWW Gateway
Lotus Notes 4.x


Can Notes be used as a POP3 Client or Server?

Notes 4.5 will include POP3 server capabilities so that users can read their Notes mail using any standard Internet mail reader such as Eudora or Netscape.

Notes 4.5 will not have client capabilities. However, there is a server add-on called POP3Fido from KEY Enterprise Solutions which will add this capability to Notes 4.x servers; this program lets Notes users read and reply to all their POP3 mail from with Notes via a single replication with their Notes server.

If you are running the OS/2 version of the Notes client, IBM has made available an early version of the POP3 client support that will be in Notes 4.6. Notes 4.6 has Eudora-like POP3 client support which you access via a location document on your Notes client.


Where can I get a Usenet News(NNTP) gateway?
There are several companies that make Lotus Notes newsreaders. These newsreaders allow users to browse newsgroups and post articles using the Lotus Notes interface. Generally, an NNTP host must be provided for the Usenet News gateways.

Lotus InterNotes News (now included with Notes 4.6)
Jsoft Technologies Notes<->Usenet Gateway

[ftp] Mike Watson's one-way Notenews Gateway for OS/2

OfficeVision and SNADS

DGA Ltd. has a set of tools for migration and co-existence of SNADS-compatible mail systems, OfficeVision and DisplayWrite.


Trusted MIME

SSE sells a secure e-mail plug-in for Lotus Notes which adds 128-bit Secure MIME support. The product is called Trusted MIME.


PalmPilot

GlobalWare has a product called Pylon Conduit which does C&S and email sync w/ the PalmPilot. They also have a product called Pylon Pro that can even convert some Notes applications to run on the PalmPilot.

Puma Technology has IntelliSync.

Lotus has EasySync but the other products have more features.


FAX

There are quite a few FAX gateways for Notes/Domino. All of these allow a user to e-mail a document to a FAX number.

Lotus' Domino Fax Server
Extracomm's ExtraFax
GFI Communication's Faxmaker for SMTP
Biscom's Fax for Notes
OMTOOL's Fax Sr.
Softlinx' Replix dominoFAX
V-Systems' VSI-FAX


POP3

POP3Fido from KEY Enterprise Solutions is an integrated server task that delivers mail to Notes users from POP3 mailboxes. A 45 day trial version is available.

POP2notes/exchange from GTI allows you to download mail from POP3 Mailbox(es) and distribute mail in Lotus Notes. The 1 mailbox version is freeware.


Migration Tools

cc:Mail (including DB8 support)
Creative Business Solutions has a cc:Mail migration tool that is more updated than Lotus'.
Lotus' Migration Tools now support DB8.

Outlook
Binary Tree has a tool which migrates mail, folder structure, appointments and meetings (including invitees and attendees), tasks, and notes.

Exchange
I/G OpenWare has a gool called Direct-TO-1 that lets email be migrated between Notes, Exchange, and a few other email systems.


MS Exchange <-> Lotus Notes

Linkage's Exchange-Notes Connector synchronizes directories, databases, and lets users send mail to each other while preserving attachments and rich-text formatting. Microsoft has bought Linkage; they bundle it for free with Exchange 5.5 and above.

MESA's JumpStart currently has does MS Exchange public folder to Notes database synchronization. They plan to have application and mail synchronization in the future.

Casahl's RA.GroupwareLink synchronizes Notes databases and MS Exchange folders.

Binary Tree's MailPort for MS Exchange migrates, mail, C&S schedules, and contacts to Notes.


NetTalk (X.500, LDAP, IMAP, Exchange, cc:Mail)

NetTalk is WorldTalk's next generation messaging backbone. It has connectors for Notes, Exchange, and cc:Mail. It is also a full-blown mail server with POP3, IMAP, and X.500 LDAP support.


Windows CE

Cadenza from CommonTime can synchronize mail, calendar, and contact info between Notes and a WinCE machine.


DOMJOBS

This mailing list contains postings of Notes/Domino jobs.

Subscribe my sending an email message to:

  requests@letterrip.nipltd.com

with this in the body of the message:
  subscribe DOMJOBS

LNotes-L

The LNotes-L mailing list is maintained by [email] Joe Ashkar. It is a Listserver based email list for Notes programmers and administrators.

Contacting the Administrator
The administrator is Joe Ashkar ([email] ashkar@ashcom.net). Email him w/ any administration problems.

Subscribing
Send a message to listproc@ozzie.notesnic.net. In the body of the letter, enter SUBSCRIBE LNOTES-L <your-name>. You will then be automatically added to the list.
To subscribe an address other than the one you are sending from, send a message to lnotes-l-mgr@ozzie.notesnic.net. In the body of the letter, enter SUBSCRIBE LNOTES-L ADDRESS. Replace ADDRESS with the address to send messages to. Approval generally occurrs within one day.
A note to users subscribing mailing list addresses - please forward the list's owner, company, e-mail address, and telephone to lnotes-l-mgr@ozzie.notesnic.net.

Unsubscribing
Send a message to listproc@ozzie.notesnic.net. In the body of the letter, enter SIGNOFF LNOTES-L. You will then be deleted from the list.
To unsubscribe an address other than the one you are sending from, send a message to lnotes-l-mgr@ozzie.notesnic.net. In the body of the letter, enter UNSUBSCRIBE LNOTES-L ADDRESS. Replace ADDRESS with the address you wish to unsubscribe. Approval generally occurrs within one day.
Note: If this does not work, you may have to unsubscribe via www.disaster.com. Follow the mailing list links to the LNOTES-L list. Get a copy of the current subscriber list mailed to you. Note the user name you are listed under. Click on the unsubscribe button and specify the email address exactly as shown.

Sending Mail to the Mailing List
Address your message to lnotes-l@ozzie.notesnic.net. Write your message and send it. It will be automatically distributed to the members of the list.
Please make sure that you don't use Return Receipt Requested or Carbon Copy back to the list!

Temporarily Shutting Off Mail Delivery
If you don't want to receive messages for an extended period of time (e.g., you go on vacation), but want to reserve your place in the queue, send a message to lnotes-l-request@ozzie.notesnic.net with a body of SET LNOTES-L MAIL POSTPONE. When you return, send a message to lnotes-l-request@ozzie.notesnic.net with a body of MAIL.

Getting All Messages from a Specific Day
Send a message to listproc@ozzie.notesnic.net with a body of GET LNOTES-L <yymmdd>.

Searching for a Specific Topic
Send a message to listproc@ozzie.notesnic.net with a body of SEARCH LNOTES-L <topic>.

Threaded Archives
Computer and Communication Technologies has a
threaded archive of the entire mailing list.


DominoLinux

DominoLinux is an open, unmoderated Internet mailing list about running the Lotus Domino Server on Linux.

Domino for Linux is an important development for the Domino community. Lotus's impending release of Domino for the popular Open Source platform is sure to introduce many people to Linux, as well as give existing Linux users access to a robust and scalable application server.

DominoLinux will be very focused on using Domino on the Linux operating system, so general questions about Domino and the Lotus Notes client are probably handled on the general Notes/Domino lists such as Domino-L (seehttp://www.nipltd.com/domino-l.htm) and LNOTES-L.

Archives of the list and other information is available at http://www.nipltd.com/dominolinux.htm

To join DominoLinux, send an email to

  join-dominolinux@lyris.nipltd.com

The content of your email is not important.

Mail to the list itself should be sent to dominolinux@lyris.nipltd.com

For assistance etc. please mail owner-dominolinux@lyris.nipltd.com


Oklahoma State Notes-L

This is a Listserver mailing list that is not quite as popular as LNOTES-L, but it is nearly always operational.

Subscribing
To subscribe, send a mail message to:
LISTSERV@LISTSERV.OKSTATE.EDU.
Leave the subject line blank, and include on the first line of the message:
SUB NOTES-L first_name last_name

Unsubscribing
To unsubscribe, send the command UNSUBSCRIBE NOTES-L in e-mail to LISTSERV@listserv.okstate.edu.

Posting Articles
Send all articles to NOTES-L@listserv.okstate.edu.

Digest Mode
It is possible to receive the contents of this list as a "digest", a periodic collection of articles from the list traffic. After receiving your subscription confirmation, send the command SET NOTES-L DIGEST to
LISTSERV@listserv.okstate.edu.

Administrative Requests
Send all other list-related commands to LISTSERV@listserv.okstate.edu. For assistance, send the command HELP.
The list owners are: [email] James Alexander and [email] Konrad Brandemuhl.

Searching
There is a Domino archive of this mailing list at http://bartok.jstechno.ch/mail/lnotes.nsf which you can use the Notes search engine on.

Archives
This list has a threaded archive accessible by web browsers.


NotesMac

NOTESMTA is an open, unmoderated Internet mailing list for users and administrators of Macs running Lotus Notes/Domino.


Archives
Archives of the list, a web interface to the list server, and other information is available at http://lists.nipltd.com/cgi-bin/lyris.pl?enter=notesmac


Subscribing
To subscribe to NOTESMTA-L, send a regular email message to:

  lyris@lyris.nipltd.com

and in the body of the note, type:
  subscribe notesmac <your name>


Unsubscribing
To unsubscribe from the list, send a message to lyris@lyris.nipltd.com with the body "unsubscribe notesmac" (without the quotes).


Posting
To post to the list, send a message to notesmac@lyris.nipltd.com.


Oklahoma State Domino-L

Subscribing
Send an email message with "subscribe DOMINO-L" in the body to LISTSERV@LISTSERV.OKSTATE.EDU.

Unsubscribing
Send an email message with "signoff DOMINO-L" in the body to LISTSERV@LISTSERV.OKSTATE.EDU.

Sending messages to the list
Send mail to DOMINO-L@LISTSERV.OKSTATE.EDU.

Archives
This list has a threaded archive for access by web browsers.


NotesMTA-L

NOTESMTA-L is an open, unmoderated Internet mailing list for administrators of MTAs and Mail gateways between Lotus Notes/Domino and other mail systems. The discussion focusses on the issues surrounding connecting Notes/Domino to other mail systems (for example the Internet, X.400, cc:Mail) using MTAs and mail gateways. Typical topics are the choice, configuration, and use of these gateways, as well as problems created by the interaction of different mailing systems.


Archives
Archives of the list, a web interface to the list server, and other information is available at http://www.nipltd.com/notesmta-l.htm


Subscribing
To subscribe to NOTESMTA-L, send a regular email message to:

  lyris@lyris.nipltd.com

and in the body of the note, type:
  subscribe notesmta-l <your name>


Unsubscribing
To unsubscribe from the list, send a message to lyris@lyris.nipltd.com with the body "UNSUBSCRIBE NOTESMTA-L" (without the quotes).


Posting
To post to the list, send a message to notesmta-l@lyris.nipltd.com.


Domino-L

Subscribing
Send a message with "subscribe DOMINO-L" to LISTSERV@lyris.nipltd.com.

Unsubscribing
To unsubscribe from the web:
Go to http://lists.nipltd.com/cgi-bin/lyris.pl?enter=domino-l, log in using your email address (from the bottom of each mail).
Choose "Leave (Unsubscribe)".

To unsubscribe via email:
Forward any message you get from the list to unsubscribe-domino-l@lyris.nipltd.com

Changing Your Mail Address
At the bottom of every message Lyris sends you, there is a sentence "You are currently subscribed to Domino-L as" followed by an email address. This is what Lyris thinks your email address is. To change this address:
Go to http://lists.nipltd.com/cgi-bin/lyris.pl?enter=domino-l, log in using your old email address (from the bottom of each mail).
Choose "Your Settings".
Change your email address.

Sending a message to the list
To send a message to all the people currently subscribed to the list, just send mail to DOMINO-L@lyris.nipltd.com.

Searching
There is an archive of this list at http://archive.tug.co.uk/Lists/DominoL.nsf which you can use the Notes search engine on.


How do you start Notes automatically on bootup in Solaris?

Here is a script you can invoke from /etc/init.d, /etc/rc3.d, or /etc/rc0.d:

#!/bin/sh
#
# agpeu * 09.04.97 * 25.07.97
#

state=$1
serverdir=${serverdir:-/data/lotus/server45}
clientdir=${clientdir:-/data/lotus/client45}
logdir=${logdir:-/data/lotus/log}
logfile=${logfile:-${logdir}/`date +%y%m%d`.log}
logfile=${logfile:-/dev/null}

domlog=${domlog:-${logdir}/domino.log}
serverlock=${serverdir}/server.lock

LOTUSDIR=${LOTUSDIR:-/vol/lotus/domino45}
export LOTUSDIR

PATH=.:/data/lotus/server45:/vol/lotus/domino45/bin:/usr/bin:/usr/openwin/bin:/usr/dt/bin:/vol/gnu/bin
export PATH

case $state in

'debug')
# Zur Anzeige der aktuellen Variablen
echo serverdir $serverdir
echo clientdir $clientdir
echo logdir $logdir
echo logfile $logfile
echo PAHT $PATH
echo LOTUSDIR $LOTUSDIR
;;

'watch')
# bringt den aktuellen LOG auf den Bildschirm
if [ -f $logfile ] ; then
echo Logfile $logfile
tail -f $logfile
else
echo Logfile $logfile ist keine Datei
fi
;;

'console')
# Starten des Notes-Clients als Server-Console im SERVER directory
cd $serverdir
echo Server Console starten `date +%y%m%d-%H%M%S`  >> $logfile
notes &
;;

'start')
# Starten des Notes Servers
cd $serverdir
if [ -f $serverlock ]
then echo Notes Server already running
else
touch $serverlock
echo "Notes Server start " `date +%y%m%d-%H%M%S`  >> $logfile
server start >> $logfile &
echo "Notes Server start " `date +%y%m%d-%H%M%S`  >> $domlog
fi
;;

'stop')
# Runterfahren des Notes Servers
cd $serverdir
if [ -f $serverlock ]
then
echo Notes Server stop   `date +%y%m%d-%H%M%S` >> $logfile
server -q >> $logfile
if [ -f *.TMP ] ; then rm *.TMP ; fi
echo Notes Server stoped `date +%y%m%d-%H%M%S` >> $logfile
echo Notes Server stoped `date +%y%m%d-%H%M%S` >> $domlog
rm $serverlock
else
echo Notes Server not running
fi
;;

'client')
# Starten des Notes-Clients im CLIENT directory
cd $clientdir
if [ -w ./notes.ini]
then notes &
else echo "Notes Client nicht installiert"
fi
;;

'kill')
# kill -9 aller Notes Server Prozesse
# Suchen und Sichern eines Core-Files
if [ -f $serverlock ] ; then rm $serverlock ; fi
ps=`ps -ef -o pid -o ppid -o stime -o args | grep /vol/lotus/domino | grep -v
grep `
if [ -n "$ps" ] ; then
echo "$ps"
echo Notes Server KILL    `date +%y%m%d-%H%M%S` >> $logfile
echo "$ps" >> $logfile
#   echo Directory >> $logfile
#   find $serverdir -name "*.n?f" -exec ls -l {} \; >> $logfile
#   echo [END] >> $logfile
if [ -f $serverdir/core ] ; then
mv $serverdir/core $logdir/core.`date +%y%m%d-%H%M%S`
fi
echo  kill -9 `ps -ef -o pid -o args | grep /vol/lotus/domino | cut -c1-6 `
kill -9 `ps -ef -o pid -o args | grep /vol/lotus/domino | cut -c1-6 `
echo Notes Server killed `date +%y%m%d-%H%M%S` >> $domlog
fi
;;

'check')
# Suchen und Sichern eines Core-Files
# Liste aller Prozesse
# Liste aller Datenbanken und -schablonen
if [ -f $serverlock ]
then echo Notes Server running
else echo Notes Server NOT running
fi

if [ -f $serverdir/core ]
then
echo "## core dump"
ls -l $serverdir/core
mv $serverdir/core $logdir/core.`date +%y%m%d-%H%M%S`
else
echo "## no core found"
fi

echo "## "
echo "## Processes"
ps -ef -o pid -o ppid -o stime -o args | grep /vol/lotus/domino | grep -v grep

echo "## "
echo "## Databasefiles and -templates"
find $serverdir -name "*.n?f" -exec ls -lL {} \;

echo "## "
;;

'clean')
# Loeschen der Log- und Corefiles die aelter als 7 Tage sind.
find $logdir  -type f -mtime +7 -exec rm {} \;
;;

*)
echo `basename $0` "[start | stop | kill | check | client | debug ]"
;;
esac

How do you set up a Digiboard under OS/2?
The following configuration setup is only a guideline. The memory address settings may very. Take the following steps if installing the Digiboard EISA board into a Compaq EISA system:
Set the 1-8 DIP Switchbox to have all switches set to OFF
Set the 1-11 Dip Switch Box to have 1, 3, and 4 set to OFF and the rest ON (This sets Memory Start Address for 0D000h and I/O Port Address for 320h)
Put the Digibaord in an empty slot on the Motherboard
Close the case on the Computer
Place the COMPAQ System Configuration Diskette in a drive
Turn on Computer
Press any key at the "Compaq System Configuration" screen
If an "Autoconfigure" screen appears, select Yes to have the computer autoconfigure the system. If the "Autoconfigure" screen does not appear and a "Welcome" screen does, press ENTER
If you selected Autoconfigure, select OK at the "Configuration" screen. If no "Autoconfigure" screen appeared, select Configure Computer from the Main Menu and press ENTER (this will process for a few minutes)
Select Step 2: Add or Remove boards and press ENTER
Select the slot number for which you entered the DigiBoard and press ENTER
Select Non-COMPAQ board and press ENTER
Place the NON-COMPAQ Option Configuration Files diskette in the drive and press ENTER
Select the Digiboard Digichannel PC/8e (or equivalent) from the Add Configuration (CFG) File screen and press ENTER
Insert the System Configuration diskette in the drive and press ENTER
Press ENTER at the "Add Confirmation" pop-up
Select the slot number for which you entered the DigiBoard and press ENTER
Confirm that the DigiBaord appears in the Slot and press ENTER (Add-Insert)
Press Esc
Press F10
Select Step 3: View or Edit Details and press ENTER
Page Down until you see the DigiBoard information
Highlight the DOS or OS/2 line and press ENTER
Select Available Resources Options and press ENTER
Press ENTER
Press F6 for Edit Resources
Press the plus (+) key until the I/O Port Address equals 320h (or whatever you set the board to in Step 2)
Press F10
Press F10 again
Select Step 5: Save & Exit and press ENTER
Select Save the configuration and restart the computer and press ENTER
If you would like to Install OS/2 at this time, insert the OS/2 Installation diskette at the "Reboot" screen and press ENTER (skip Step 1 of Installing OS/2 2.1). If you do not want to install os/2 at this time, turn the computer off at the "Reboot" screen.
Installing DigiBoard Software:
Go to the OS/2 Full Screen prompt
Type MD DIGI and press ENTER
Type CD DIGI and press ENTER
Insert the Digiboard Diskette in the drive
Type COPY A:\OS2\*.* and press ENTER
Editing the CONFIG.SYS
Go to the OS/2 Full Screen prompt
Type E CONFIG.SYS and press ENTER
Go to the end of the line that says "DEVICE=C:\OS2\MDOS\VWIN.SYS" and press ENTER
Type DEVICE=C:\DIGI\XALL.SYS /n:3 /a:q /b:57600 /d:N8 1 /p:320 /m:D0000
Save the CONFIG.SYS by pressing Alt-F4 and selecting Save

How do you change the new mail sound on a Mac?

You can use ResEdit to change the "New mail Sound" resource in the Notes executable:

1) Make a copy of your Notes program.
2) First convert your gotmail.wav (if you have a .wav file) to a gotmail.snd.
3) Open the gotmail.snd with ResEdit.
4) Open the Notes program with ResEdit.
5) Open the snd resource group of Notes.
6) Find the "New mail Sound" snd resource in Notes, make a note of its resource ID (should be 9000).
7) Delete this resource.
8) Copy the gotmail snd resource from the gotmail.snd file.
9) Paste it into Notes.
10) Rename it to "New mail Sound", renumber it to the correct ID number.
11) Save Notes.


How do you set up server proxying through MS Proxy Server?

From Mark Kaynor (mkaynor@daa.com)

I recently spent an inordinate amount of time setting up server proxying on MS Proxy Server 2.0 such that a Domino server or Notes client outside the proxy (the "external server") could replicate w/ and route Notes email to a Domino server inside the proxy (the "internal server"). Information was sparse and I had to glean bits and pieces from several, sometimes conflicting, sources of
information. I could have saved myself hours of frustration had I been able to find a document similar to this. No guarantees, but this should get one pointed in the right direction.


If problems occur, don't forget to check the event log on the internal server - the proxy client writes messages to the event log which can be very helpful during configuration and troubleshooting. BTW - both Domino servers are running v4.6.4 on NT 4.0, SP5., the proxy server in running on NT 4.0, SP3 w/ roll-up hotfix and Option Pack 4.

1) Obtain and install the Proxy Server hotfix - make sure to compare installed files date and size w/ those listed in the supplied "readme.txt" file after installation. MS tech support told me that setting up server proxying was pretty much futile w/o the hotfix. The file emailed to me was:

     prxyfixpacki.zip         308,819 bytes        6/28/99 11:45a

2) To simplify the initial setup, temporarily disable Winsock Proxy Access Control if enabled. Clear the WinSock Proxy | Properties | Permissions | "Enable access control" checkbox.

3) Also temporarily disable Packet Filtering if enabled. Clear the WinSock Proxy | Properties | Service | Security | "Enable packet
filtering on external interface" checkbox.

4) Set proxy client configuration to connect to proxy via IP address. Select WinSock Proxy | Properties | Service | Client Configuration | Clients connect to Microsoft WinSock Proxy Server by | "IP Address" checkbox.

5) On the proxy server, disable default gateway and IP forwarding on internal NIC. Clear Control Panel | Network | Protocols | TCP/IP Protocol | IP Address | "Default Gateway" entry. Clear Control Panel | Network | Protocols | TCP/IP Protocol | Routing |
"Enable IP forwarding" checkbox.

6) Add port 1352 to the SSLPortListMembers list in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3Proxy\Parameters (see Microsoft Knowledgebase article Q184028 <http://support.microsoft.com/support/kb/articles/q184/0/28.asp>. Run REGEDT32. Go to
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3Proxy\Parameters. Open "SSLPortListMembers". Add 1352 twice to the list - it should end up looking something like:

          443
          443
          563
          563
          1352
          1352

7) Reboot the proxy server

8) Reinstall proxy client on internal server. Reboot internal server

9) Test client installation on internal server by running "chkwsp /f", located in the MS Proxy Client install directory (default is "c:\mspclnt"). Success = "Client control protocol version MATCHES the server control protocol."

10) Create and save WSPCFG.INI file on internal server in same directory as NSERVER.EXE ("C:\Notes", for example) as follows:

     [Common Configuration]
     ServerBindTCPPorts=1352
     Persistent=1
     KillOldSession=0

11) Reboot internal server - proxy client on internal server should now bind to port 1352 on proxy server

12) Open CMD prompt, test proxy client connection using "ftp ftp.microsoft.com". Success = ability to logon anonymously to ftp.microsoft.com and do a directory listing

13) From the Internet <preferably from an entirely separate connection> try to telnet to port 1352 on the proxy server's external IP, eg.:
Start | Run | "telnet.exe"
Select "Connect"
Select "Remote system"
Port: 1352 <Windows Telnet defaults to Port: Telnet>
Address: <proxy server's external NIC IP address>
Success = after connecting, the "Disconnect" selection is available under main menu "Connect"
Disconnect, close Telnet

14) Create a "Local Area Network" TCPIP connection document on the external server (or client) that points to the internal Domino server name using the proxy server's external NIC IP address.

15) Remove all entries in "Web Proxy" section of current location document on external server (or client)

16) Open Notes client on external server and trace a connection to the internal server. "File | Tools | Preferences | Ports | Trace Connection", select internal server. If successful, go to step 20.

17) Stop external server Domino services <"quit" at Domino terminal> (we had an active dialup modem connection that was screwing up the ability of the internal server to bind to proxy server port 1352 - stopping the outside Domino service removed that conflict so we could test)

18) Reboot internal server - client should now successfully bind internal server to proxy server port 1352


19) Still having problems? Use "netstat -an" to review port bindings on proxy server, internal and external servers. Proxy server should show port 1352 bound to internal server's IP address. You can't continue past here until you can "see" the internal server from the external server via the proxy server's external IP address.

20) Restart external server Domino service and make sure everything works correctly.


To enable access control:

21) Create new user in "User manager for domains", as a member of the "Domain Users" group

22) Grant this user "Policy | User Rights| Log on locally", also in User Manager for Domains

23) Re-enable Access control on proxy server

24) Add new user to "Unlimited access" (for security reasons you should change this to a custom protocol later)

25) Open command prompt on internal server

26) Make "c:\mspclnt" your current directory (assumes default proxy client installation location)

27) Create credentials for nserver.exe, nrouter.exe, and nreplica.exe as follows:

     credtool -w -n nserver -c NewProxyUser Domain Password
     credtool -w -n nrouter -c NewProxyUser Domain Password
     credtool -w -n nreplica -c NewProxyUser Domain Password

where NewProxyUser is the new user created in step 21, Domain is the NT domain to which the proxy server belongs, and Password is the password assigned to NewProxyUser. The credentials for each service can be checked by replacing the "-w" <write> in the above commands with "-r" <read>

28) Add the line "ForceCredentials=1" to the WSPCFG.INI file you created in step 9. e.g.:

     [Common Configuration]
     ServerBindTCPPorts=1352
     Persistent=1
     KillOldSession=0
     ForceCredentials=1

29) Reboot the internal server

30) Test that the outside and internal servers can still communicate correctly

To enable packet filtering

31) In WinSock Proxy Security, select "Enable packet filtering"

32) Add two custom filters as follows:

     Protocol: TCP
     Direction:     In
     Local port:    Fixed, 1352
     Remote port:   Any
     Local host:    Default Proxy Server external IP addresses
     Remote host:   Single host, <external server IP>

and
     Protocol: TCP
     Direction:     Out
     Local port:    Any
     Remote port:   Fixed, 1352
     Local host:    Default Proxy Server external IP addresses
     Remote host:   Single host, <external server IP>

33) Test that the external and internal servers can still communicate correctly


Which file system should be used for the Notes server?
OS/2 has three supported file systems: FAT, HPFS, and HPFS386.

The OS/2 2.0+ implementation of FAT is 32-bit and gets slightly higher performance than the HPFS file system shipped with OS/2 2.0+. However, when a large number of files is created and destroyed on a FAT file system, it tends to get fragmented more than a similiar HPFS file system would.

The normal HPFS that is shipped with OS/2 2.0 and above is still 16-bit. There are some rumors that IBM will ship HPFS386 with OS/2 eventually, however. HPFS smart caching takes up more memory than a FAT system.

HPFS386 comes with IBMs Lan Server Advanced. It is fully 32-bit and gives a 10-15% performance gain over the regular version of HPFS. Lan Server does not have to be used on the OS/2 system, but it must be installed and a license purchased to legally use HPFS386.

How do you set up IWP forms input when running Microsoft IIS as the web server?

The ability to use a cgi script like inotes (the forms input helper for Internet Web Publisher) is dependent on an NT registry variable "CreateProcessAsUser". The solution is to manually add it with a value of 0

Caution: Manually editing the registry is potentially dangerous, and giving the CreateProcessAsUser variable a value of 0 is likewise a security risk according to the IWP documentation.

1) From the WINNT35\System32\ directory, run the REGEDT32.EXE program
2) Select the HKEY_LOCAL_MACHINE window and trace the following path: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters
3) With the Parameters Folder highlighted, select "Edit" from the menu and then select "Add Value" which should bring up the following dialogue box. Fill in Value Name with "CreateProcessAsUser", select REG_DWORD as the Data Type, and set the value to 0.


How do you tune the operating system for running Notes?

Add the following kernel tuning additions to /etc/system:

 set max_nprocs=4096
 set strctlsz=4096
 set shmsys:shminfo_shmmax=268435456
 set shmsys:shminfo_shmseg=600
 set shmsys:shminfo_shmmni=512
 set shmsys:shminfo_shmmin=1
 set semsys:seminfo_semmns=4096
 set semsys:seminfo_semmni=4096
 set semsys:seminfo_semmnu=4096
 set semsys:seminfo_semume=64
 set semsys:seminfo_semmap=512
 set semsys:seminfo_semmsl=128

In your notes.ini, also add:

 Disable_Locking=1

Which platform is best for a Notes server?

The best platform depends on the software you need to run and local politics :-)

Most new Notes software used to appear first on the OS/2 platform because that is what the Notes server was originally developed to run on. With Lotus support of additional platforms, more software is appearing simultaneously on other platforms with Windows NT being the second most popular in terms of software availability. However, as of Notes 4.x, Lotus has switched to developing on NT first because of the better development tools on that platform; some Notes add-ons only work on Win32 (Windows NT and Win95) and the Notes client works best on Win32.

Unix support is much better in R4, but the 3rd-party developers continue to write for NT as the main target platform.

For serious numbers of users per server, look at the AS/400 native port; there have been reports that over 10,000 users (using partitioned servers) can be placed on it without any problems.

Performance evaluations are available from:
* IBM
* NotesBench


How do you get NT to reboot automatically after the Blue Screen Of Death?

Using regedit, change the registry key:

  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\CrashControl\AutoReboot

to have a DWORD value of 1.


How do you generate a core dump for IBM to look at?
There is a program in the OS2 directory or a subdirectory of it called DDUMP.EXE. This program will create a dump disk for you to use when you get a trap like this one.
Once the server crashes with the trap insert the dump disk and hit the following keys:

Control - Alt - NUM LOCK --  NUM LOCK  (Yes, hit NumLock key twice.)

Just a word of caution. 48 MB of ram created 25 Disks. The dump Disk is needed to start the memory dump.

Where can I find info on Mac-specific (not Notes-related) problems?

Check the following WEB sites:

* The Macintosh Resource Page
* The MacInTouch Home Page
* The Cult of Macintosh
* The EvangeList Web Site

If those don't have an answer to your Mac questions, they have links to numerous other sites for software downloads and other software and hardware questions. In addition, there is the I/O MUG - Internet ONLY Macintosh User's Group mailing list. To subscribe, send
SUBscribe IO-MUG <full name>
to
LISTSERV@UTARLVM1.UTA.EDU


How do I install Notes as an NT Service?

Switch to the Notes server's program directory in the command prompt.
Type "ntsvinst -c", then exit back to program manager.

This makes the Notes Server a manual NT service. To make it automatic, go to Control Panel/Services and select Automatic under the start up options for Notes.

If you cannot find the ntsvinst.exe program, you probably didn't install it. Rerun the Notes install, choose the Custom install option, and select the Run As NT Service option.


How do you get the Notes server to run in the background?

Run this as part of your system startup code in /etc/inittab:

if [ -d /usr/lotus/notes/notesr4 \
   -a -f /opt/lotus/bin/server \
   -a -f /usr/lotus/notes/autostart.server ]; then
  PATH=/opt/lotus/bin:/usr/lotus/notes/notesr4:$PATH su notes -c \
     'server </dev/null >/dev/null 2>&1' &
  sleep 10;
  echo 'Notes server started'
fi


Why can't Notes clients see my new Notes server running IPX?

The SAP Agent is not installed on NT by default when you install SPX/IPX. Install this and the Notes clients should have no problems communicating with the Notes server.


How do you set up NetBIOS?

For Notes 3.x, NetBIOS must be on port 0 under NT. Under Notes, the NetBIOS port must be on LAN Unit 0.
For Notes 4.x, you can set the LANA number. The Unit number in the Notes port setup has to match the Nbf LANA number in NT's protocol configuration (look under ControlPanel/Network/Services/NetBIOS).


How do you change the new mail tune under NT?

You can add this to a button you can send to your users (note the hardcoded .wav file path though):

Sub Click(Source As Button)
 ' by Lance I. Zakin
  Dim session As New NotesSession
  Dim fileName As String
  Dim choice As String
  Dim verify As String
  Dim Path As String

  fileName = Dir("C:\WINNT\MEDIA\*.WAV")
  Path = "C:\WINNT\MEDIA\"

  Print fileName
  choice = Inputbox$("Click OK to install, otherwise CANCEL to select another Tune.", "Install New Mail Tune", Path & FileName)

  Do While fileName <> "" And choice = ""
    fileName = Dir()
    Print Path & fileName
    choice = Inputbox$("Click OK to install, otherwise CANCEL to select another Tune.", "Install New Mail Tune", Path & FileName)
  Loop

  Call session.SetEnvironmentVar( "NewMailTune",  choice, True)

  Msgbox "Completed!  Restart Notes to initiate " & choice & " as your New Mail Tune.", , "Install New Mail Tune"
  Print "Restart Notes to initiate " & choice & " as your New Mail Tune."
End Sub

How do you determine the NT Service Pack Level using LotusScript?

Put this code into a button:

(Declarations)
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (Byval hkey As Long, Byval lpSubKey As String, Byval ulOptions As Long, Byval samDesired As Long, phkResult As Long) As Long
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (Byval hkey As Long, Byval lpValueName As String, Byval lpReserved As Long, lpType As Long, Byval lpData As String, lpcbData As Long) As Long
Declare Function RegCloseKey Lib "advapi32.dll" (Byval hkey As Long) As Long

Const HKEY_LOCAL_MACHINE = &H80000002
Const SYNCHRONIZE = &H100000
Const STANDARD_RIGHTS_READ = &H20000
Const KEY_QUERY_VALUE = &H1
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
Const ERROR_SUCCESS = 0&
Const REG_SZ = 1

Sub Click(Source As Button)
     ' from Paul Ray @ IRI_SOFTWARE
     Dim hKey As Long, result As Long, length As Long
     Dim sValue As String
     
     ' open the key
     result=RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion", 0, KEY_READ, hKey) 
     
     If result <> ERROR_SUCCESS Then
          Messagebox "Can't open key"
     Else
          sValue=Space$(128)
          length=128
          
          ' query the value of the key
          result=RegQueryValueEx(hKey, "CSDVersion", 0, REG_SZ, sValue, length)
          
          ' display it
          If result = ERROR_SUCCESS Then
               Messagebox Left$(sValue, length) 
          End If
          
          ' close the key
          Call RegCloseKey(hKey)  
     End If
     
End Sub


How do you back up the server automatically?
Create a batch file with the following commands:

@echo off
net stop Lotus Notes Server
ntbackup BACKUP c:\ /D Notes Server Backup /hc:on /B /T Normal
net start Lotus Notes Server

This assumes that the Notes server is running as a Windows NT service and the server Notes ID is not password-protected.

How do you set up the modem port for Solaris 2.x?
Notes expects the Notes port name to match the /dev name. Do not enable getty on this port. Install Sun Patch 100513-04. Set hardware handshaking in the EEPROM.

How do you run the Notes server in the background but still be able to control the console?

You can use the GNU program called Screen to run the Notes server. You can then detach and re-attach to this window as needed from any telnet session. You can find it at any GNU software archive.

For Linux and Solaris, you can modify your rc3.d script to include this line:
su - notes -c "screen -d -m -S NotesServer server"


Why don't bitmaps display properly on some systems?

Notes uses a specific set of 256 colors for display; Notes will force all images to be displayed using these colors. On systems that have video drivers that have 256 colors or less, you will have to use the same 256 colors that Notes uses. On systems with more than 256 colors, this is not an issue.

The palette is available below in several formats:

Adobe Photoshop:

MS Paint (Win95 and NT): lotus.pal
Corel Draw: lotus.cpl


How do you write DbLookups so they work on a local database and on the server?

Use @Dbname to test for the location using these formulas::

DBName := @Text(@DbName);
Server := @Subset(DBName; 1);
Database := "KeywordLookup";
ClassCache := "Notes" : "NoCache";
View := "LookupKW";
Key := "Key Name";
@DbLookup(ClassCache; Server : Database; View; Key; "Ret_Value")

Now you can substitute the Server and Database variables everywhere in the Notes application. DbLookups or @Commands will automatically run local when the user is local and run on the server when the user is on the server.


How do you display a button next to a field only when editing?

Duplicate the line with the field and button and remove the button from the copy.
Change the field to a computed-for-display field with a formula of just the name of the original field.

Mark the original line hide when reading, and the copy hide when editing.


How do you restrict a field to contain alphanumeric characters only?

This is an example of code that uses regular expressions to limit a field's entry. Put this in a field's Input Validation formula:

  @If(
    @Matches(Serial_Num; "+{0-9}"); @Success;
    @Matches(Serial_Num; "+{a-zA-Z}"); @Success;
    @Do(@Prompt([OK]; "Invalid Serial Number"; "The Unit Serial Number contains an illegal character, probably a carriage return.  Please remove the illegal character and save again."); @Return(""))
  )


How do you validate that a field has alpha characters only?

Use the following for an Input Validation Formula:

@matches(string;"+{A-Za-z}")


How do you total a column at the bottom of a view?
Use this definition for a different column in the view:

@Subset(@DbColumn("" : "NoCache"; ""; "Report Month Dollars"; 3); -1)

The subset -1 tells it to just return the total.

Can you have views based on the current user name?

If you have a Notes client, the best thing to do is to have a shared view set to Personal On First Use; whenever you redesign the view, you will have to remove the database icon or bookmark and then re-add it to get the new design. The technique which follows keeps the view on the server, but it is very resource intensive.

In the Advanced tab of the view properties, set Refresh Index to "Automatic" and Discard Index to "After each use".

In the selection formula for the view, select only documents which the current user can read. E.g.,
@IsMember(@UserName; ReaderList)

You cannot hide the categories that are not for the reader, so you should use an uncategorized view.

Warning: This is extremely server intensive since it will cause the server to rebuild the view each time a user looks at it!


How do you categorize and count the number of documents created in a particular week?

Category field (Date format, "Created" is the field with the creation date):

        @adjust(Created;0;0;1-@weekday(Created);0;0;0)

Summation field (number format, that's right, just a number 1 to total up):

        1

This creates a view catagorized by a field that has the "previous Sunday" computed.
Set up category totals in the view for the summation field and you'll have what you want.


How do you reduce database size by deleting unused fields?

Delete the fields before the doc is saved by adding code like this to the fields' translation formula:

  @If (x="";  @DeleteField;  x)

Make sure the x's are exactly the field name, or you will loose data.
Do not delete fields if they are used in other formulas.


From a response document, how do you update a field in the parent document?

Use

  @SetDocField($Ref;"Field on Parent Doc";"Value") 

in a formula in a field on your response doc. When the response is saved, the parent will be updated. The $Ref parameter is the document number of the parent document which is always stored in the response document.


Can LotusScript operate on Private Views?

No. This is a limitation in LotusScript.


Can you have an agent send mail as a specific person?

In LotusScript, use the CopyToDatabase method of the NotesDocument class to copy a document into mail.box (on the server) without any Paste agents or server tasks overwriting any fields. The document must have the SendTo, Recipients, From, Subject, and Body field set properly. The Form field must be set to "Memo".

You also use the CreateDocument method of the NotesDatabase class to create a document directly in mail.box. The message will be routed as soon as you call the Save method.

This can only be done on the server. If it is done via the client, the From field will be overwritten during the replication process.


How do you get the directory the current database is in?

Public Function GetDatabasePath( db As Notesdatabase ) As String
  Dim position As Integer
  position = Instr( db.FilePath, db.FileName )
  GetDatabasePath = Left( db.FilePath , position - 1 )
End Function


How do you automatically copy an ACL from a template into a new database?

If you enclose the ACL's in bracket's, like so:


[-Default-]
No Access
[Administrator]
Manager
[LocalDomainServers]
Manager
[OtherDomainServers]
No Access

they will be copied automatically to any new databases you create using that template. However, role information is not copied automatically.


How do you display a number field with leading zeroes?

For a number with exactly 5 characters in its display:

  textnum := @Right("00000" + @Text(num);5);


How do you add more action buttons than fit on the display?

For FORM action buttons, you can give the user access to all ten buttons by adding a "scroll" action button. Divide the ten buttons into two groups of five, and for the buttons in the first set, set the Hide-When formula to ABar != "Set1". For the buttons in the second set, set the Hide-When formula to ABar != "Set2". Add a computed field to the form called ABar, and give it a value of "Set1" (this sets the default). Add another action button (this is your scroll button), leave it nameless, choose the right-arrow icon for it, and give it the following formula:

NewABar := @If(ABar = "Set1"; "Set2"; "Set1");
@SetField("ABar"; NewABar);
@Command([RefreshHideFormulas]);

For VIEW action buttons, the Hide-When formulas should be @Environment("ABar") != "Set1" for the first
set and @Environment("ABar") != "Set2" for the second set. Give the scroll button the following formula:

CurBar := @Environment("ABar");
NewBar := @If(CurBar="Set1";"Set2";"Set1");
@SetEnvironment("ABar"; NewBar);
@Command([RefreshHideFormulas]);

If you need more than two sets of buttons, just extend this logic.


How do you prevent a form from prompting to save it?

Create a hidden field with the name SaveOptions and make it computed with value "0" (zero in quotes).

How do you automatically filter mail in Notes?

1. Create a folder in your mail database to hold the mail from the mailing list.
2. Create an agent in your mail database.
3. Give it a name.
4. Specify it as "If new mail has arrived".
5. Mark that the agent will run a script, as opposed to simple action or formula.
6. In the Event field, choose Initialize and enter the following script:

Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim collection As NotesDocumentCollection
Set db = session.CurrentDatabase
Set collection = db.UnprocessedDocuments
For i=1 To collection.Count
  Set doc=collection.GetNthDocument(i)
  If doc.ReplyTo(0) = "lnotes-l@ozzie.notesnic.net" Then
    doc.PutInFolder( "Mailing List\L-Notes" )
    doc.RemoveFromFolder( "($Inbox)" )
  End If
Next
End Sub

This will place all mail from the mailing L-Notes mailing list and place it in the folder named "Mailing List\L-Notes" whenever the mail comes in. You can add additional Else statements for any other mailing lists you are subscribed to.
Your administrator will have to give you access to Run Restricted Agents in the server document for your mail server.


How do you create a view action button that creates responses to only work on main documents?

You can check for the Form type of the document that the user is creating a response document for as follows:

@If(Form="Main";
  @Command([Compose];"Response");
  @Prompt([OK];"Select Main";
    "Select a Main document for which you wish to create a response.")
)

How can you tell if a field has been changed in LotusScript?

Make a global variable named "X" which is the same data type as the field you want to monitor.
In the PostOpen event for the form, set X to the value of the field.
In the QuerySave event check to see if the current value of the field is still the same as X.


Can you inherit fields from parts of the same form?

Yes, as long as the field you wish to inherit into is below the field you want to inherit from.

This means if have field B below field A, field B can reference the contents of field A in it's computed formula.


How do you do a mail merge using info from existing documents?

A user wants to select a number of customer documents and then run a macro which composes a standard document for each of the selected customer documents.

Have the macro's Operation set to Compose new documents when run.
In the Formula add a statement:

  FIELD Form := name_of_the_standard_document_form;

The form to be composed should have inherit turned on so fields from the selected docs will appear in the new form.

If you only need to print out forms with existing data, this is even simpler. Highlight the documents in the view and then select File, Print, Form Override.

How do you generate sequential document IDs?

Computer Associates sells a sequential number generator as part of the QXCOM Tools.

A company called Sentor Communications also has a product called SequelNum. Call (+61 2 9391 0544) or [email] email for more info. The list price is US$155 or AU$195.

Under Version 4, you can use a triggered agent on the server which uses a locked file like so:

  Sub Initialize
  file% = Freefile
  Open "c:\\seqnum.bin" For Binary Access Read Write Lock Read As file%
   ' You can also use Open "\\NotesServer\SharedDirectory\seqnum.bin"
   ' if your client and server are Win95 or NT based.  Open can take
   ' a UNC path
  Get #file%, 1, SeqNum%
  SeqNum% = SeqNum% + 1
  Put #file%, 1, SeqNum%
  Close file%
  End Sub

This method does solve the race condition possible if you use the "field stored in a document technique", but the limitation of this is that it won't work with replicated databases (user or server). However, note that this agent cannot be run from the client because running from the client will cause the sequential numbering file to be created on the client machine.

Here is another technique that will work only if your client machines access a non-replicated database on a single server:

' MBCounter&(CounterName$, CounterToSave%)
'
' Marco Beri 
' marcob@equalis.it
'
' This functions give one or more progressive unique counters without race conflict condition
'
' Parameters:
'    CounterName$: counter name; every counter name represents a different counter; you could have as many counters as you want
'    CounterToSave%: if false MBCounter& just returns next free number, if true it gives you next free number and increment it by one
'
' Return value:
'    a long integer
'
' Usage:
'   MBCounter("EveryCounterNameYouWant", False) in QueryOpen if and only if it is a new document and just to display the next free number.
'   MBCounter("EveryCounterNameYouWant", True) in QuerySave if and only if it is a new document, just before exiting and only if you really
'   save the document (so you are sure not to waste a free number)
'
' 
Attention:
' - you cannot use form, view or folder with a name like (MBCounters); if you need this name change COUNTER_FOLDER_FORM_NAME$ constant value
' - if you want you can create a view to visualize the document with form COUNTER_FOLDER_FORM_NAME$ to check the counter values
'

Option Public
Option Explicit
Const COUNTER_FOLDER_FORM_NAME$="(MBCounters)"

Function MBCounter&(Byval CounterName$, Byval CounterToSave%)
     On Error Goto MBCounterError

     Dim CounterFieldName$
     Dim session As New NotesSession
     Dim db As NotesDatabase
     Dim view As NotesView
     Dim doc As NotesDocument
     Dim docNext As NotesDocument
     Dim CounterValue&
     Dim FieldValue As Variant
     Dim Ret%
     Dim item As NotesItem     
     Dim FolderToBeCreated%
     
     CounterFieldName$ = "MB"+CounterName$
     Set db = session.CurrentDatabase
     Set view = db.GetView(COUNTER_FOLDER_FORM_NAME$)
     If view Is Nothing Then
          FolderToBeCreated%=True
     End If
     
     Do
          If Not FolderToBeCreated% Then
               view.refresh 
               Set doc = nothing
               Set doc = view.GetFirstDocument()
          End If
          If doc Is Nothing Or FolderToBeCreated% Then               
               Set doc = New NotesDocument(db)
               doc.Form = COUNTER_FOLDER_FORM_NAME$
               Call doc.Save(True, False)
               doc.putinfolder COUNTER_FOLDER_FORM_NAME$
               If FolderToBeCreated% Then
                    Set view = db.GetView(COUNTER_FOLDER_FORM_NAME$)
                    FolderToBeCreated% = False
               End If
          Else
               Set item=doc.GetFirstItem(CounterFieldName$)
               If item Is Nothing Then
                    Call doc.ReplaceItemValue( CounterFieldName$, 0 )
                    Call doc.Save(False, False)
               Else
                    FieldValue=doc.GetItemValue(CounterFieldName$)
                    If Not CounterToSave% Then
                         CounterValue&=FieldValue(0)+1
                         Exit Do
                    Else
                         Call doc.ReplaceItemValue( CounterFieldName$, FieldValue(0)+1)
                         Ret%=doc.Save(False,False)
                         If Ret% Then
                              CounterValue&=FieldValue(0)+1
                              Exit Do
                         End If
                    End If
               End If
          End If
     Loop

     ' This deletes double docs incidentally created in the Loop (almost impossible 
     ' to happen, just first time and not a problem, but just to be clean)
     ' [For the race condition at the start if two users access an uninitialized
     ' counter at the same time.  The best workaround for this is to create
     ' the initial counter by hand..Ed.]
     Set doc = view.GetNextDocument(doc)
     Do While Not doc Is Nothing
          Set docNext = view.GetNextDocument(doc)
          Call doc.Remove(True)
          Set doc=docNext
     Loop
     
     MBCounter& = CounterValue&
     
MBCounterExit:     
     Exit Function
     
MBCounterError:     
     Msgbox "MBCounter", Err, Error$
     MBCounter& = -1
     Goto MBCounterExit
End Function


Can you show FTSearch documents with a specific view?

Add a private on first use folder named SearchResults.

In this folder, add two action buttons. One should empty out the folder and the other should prompt the user using dialog boxes to build the query.

For the query, use the Lotuscript FTSearch method on the database. This will return a NotesDocumentCollection. You can then use the PutAllInFolder method to move the documents in the collection into SearchResults. You then have to refresh the view.


How do you make a view to use for checking for replication conflicts?

Conflict documents contain the field $Conflict, so you could use

  Select @IsAvailable($Conflict)

in a view's selection formula. Also, be sure "No Response Hierarchy" is on in the view attributes since conflict documents are response documents.


Can you access the Clipboard in Notes?

This function (thanks to Manfred_Doerwald@IDG.DE) calls Win32 functions to put a field in the clipboard:

This goes in (Options):

'dataformat ID for ANSI text with ending null (\0). CR(13)/ LF(10) are for end of line.
Public Const CF_TEXT =  &H001

This goes in (Declarations):

Declare Function OpenClipboard Lib "User32.dll" Alias "OpenClipboard" (Byval hWnd As Long) As Long
Declare Function EmptyClipboard Lib "User32.dll" Alias "EmptyClipboard" ( )  As Long
Declare Function SetClipboardData Lib "User32.dll" Alias "SetClipboardData" (Byval wFormat As Integer,Byval hAnsiText As Long ) As String
Declare Function GetClipboardData Lib "User32.dll" Alias "GetClipboardData" (Byval wFormat As Integer) As String
Declare Function CloseClipboard Lib "User32.dll" Alias "CloseClipboard" ( ) As Long

Declare Function MYlstrcpy Lib "Kernel32.dll" Alias "lstrcpyA" (Byval Buffer As Long, Byval COPYString As String) As Long
Declare Function GlobalAlloc Lib "Kernel32.dll"  Alias "GlobalAlloc" (Byval wFlags As Long, Byval dwBytes As Long) As Long
Declare Function GlobalLock Lib "Kernel32.dll" Alias "GlobalLock"(Byval hMem As Long) As Long
Declare Function GlobalUnlock Lib "Kernel32.dll"  Alias "GlobalUnlock" (Byval hMem As Long) As Long
Declare Function GlobalFree Lib "Kernel32.dll"  Alias "GlobalFree" (Byval hMem As Long) As Long

This goes in the Click event for a button:

Sub Click(Source As Button)
  Dim Status As Long
  Dim ptr As Long, ghand As Long,handle As Long
  Dim Text As String
  Dim workspace As New NotesUIWorkspace
  Dim Uidoc As NotesUIDocument
  Dim item As NotesItem
  Dim s As New notessession
  Dim db As NotesDatabase
  Dim col As NotesDocumentCollection
  Dim doc As notesDocument
     
  Set db = s.currentdatabase
  Set col = db.unprocesseddocuments
  Set doc = col.getfirstdocument
     
  ' Control of platform 16/32-Bit
  If Instr(s.platform,"16") Then
    Messagebox ("Wrong Windows-platform; this agent runs only under Windows NT/95")
    Exit Sub
  End If
  ' Select Notes field
  Set item = doc.GetFirstItem("xxxxxx")
  ' open clipboard
  Status =  OpenClipboard(handle)
  If Status <> 0 Then
    ' Example: reading clipboard contense
    'Text = GetClipboardData(CF_TEXT)
    'Delete clipboard contense
    Status = EmptyClipboard()
    ' for testing purpose make a textstring
    'Text =   "Manfred Doerwald"
    'get global storage for field contense
    ghand = GlobalAlloc(0,(Len(item.Values(0))+1))
    'or global storage for textstring contense
    'ghand = GlobalAlloc(0,(Len(Text)+1))
    'lock global storage
    ptr = GlobalLock(ghand)
    'copy contense of  field to global storage
    Status = MYlstrcpy(ptr,item.Values(0))
    'or copy of textstring contense
    'Status = MYlstrcpy(ptr,Text)
    'free global storage
    Status = GlobalUnlock(ghand)
    'write to clipboard
    Call SetClipboardData(CF_TEXT, ptr)
    'close clipboard
    Status = CloseClipboard()
    'free handle of global storage
    Status = GlobalFree(ghand)
  Else
    Messagebox ("Error opening the clipboard!")
    Exit Sub
  End If
End Sub


How do you save a document, then create a new document in its window?

@Command([FileSave]);
@Command([FileCloseWindow]);
@PostedCommand([Compose];"";"test2");


How do you force the value of a field to be unique?

This assumes you have a field named CompanyCode as an editable field. It also assumes that you have a view called "Company Code" which has CompanyCode column.

Use the following input validation formula for CompanyCode:

  @If(
       CompanyCode = "";
         @Failure("You have to fill in Company Code");
         @IsError(
             @DbLookup("" : "NoCache";  ""; "Company Code"; CompanyCode; CompanyCode));
           @Success;
         @IsNewDoc = 0;
           @Success;
       @Failure("The company code you entered has already exist, please change it")
     )

This formula first checks to make sure a value is entered. If a value is entered, it then uses that value as a key to lookup into the Company code view for a document containing that company code; if no document with that code is found, an error condition is created, which satisfies the @IsError @Function, and returns @Success. If a document with that code is found, the code is returned, which does not satisfy the @IsError function, causing the @Failure message to be returned.


How do you find the positions of a string in a text list?

Field - List = your input list
Field - FindChar = the thing you're trying to find in the list
Field - Position = multi value field with final position of the characters you're looking for.

Button code used to find the position of all of your characters:

NumInList := @Elements(List);
TargetFindList := @Explode(@Repeat(FindChar + ", " ; NumInList -1) + FindChar);
SeqList := @Text(@TextToNumber(("0":"1":"2":"3":"4":"5":"6":"7":"8":"9") *+
  ("0":"1":"2":"3":"4":"5":"6":"7":"8":"9")));
Seq := @Subset(@Subset(SeqList; -99); NumInList);
AltFindList := List + Seq;
AltTargetFindList := TargetFindList + Seq;
FindPos := @Replace(AltFindList; AltTargetFindList;Seq);
Final := @Trim(@Replace(FindPos;AltFindList;""));
@SetField("Position";@Trim(@Replace(FindPos;AltFindList;"")))


How do I get the week ending date for a specific day?
Assuming tdate contains the day you'd like to convert:

@If(tdate != ""; @Adjust(tdate; 0; 0; @Modulo(8 - @Weekday(tdate); 7); 0; 0; 0); tdate)

Why does @Explode only give me the first item?

The problem is that @Explode stops when it encounters a space or a period. You need to replace them as shown below:

 TextSrting := @ReplaceSubstring(@ReplaceSubstring(@Implode(TextList;"~");" ";"^");".";"`");
 NewTextList := @Explode(TextString;"~")

This example replaces space with "^" and periods with "`" before you do the explode. If you use elements of the new textlist, remember to convert these characters back to spaces and periods.


How do you delete Environment variables from the notes.ini file?

ENVIRONMENT environmental variable := ""; 

If you're inside a formula, use this instead:

@SetEnvironment("environmental variable";"").


How do you prevent people from viewing with a different form and saving the result?

Method 1


Create two fields, 'origForm' and 'formCheck'. 'origForm' is computed when composed with the formula: Form. The 'formCheck' field is a hidden editable field with a translation formula of:

@If(@IsNewDoc=0 & origForm <> Form; @Prompt([OK]; ""; "You cannot use the view menu to compose new documents.  Use the Compose menu or buttons.  You will not be permitted to save this document"); "");

In the validation formula, there is a copy of the above formula with @Failure instead of the @Prompt.

Method 2

1. Take all the forms out of the Compose menu. This will remove them from the View menu.

2. Add buttons for Compose. You can set up a Menu form or document with buttons on it, from which all Compose and View statements are executed. You can put this menu in a separate database or if you put in in the same database, create one instance, and then hide the form from the Compose menu.


Can you use @UserName in a view?

You can use @UserRoles and @UserName in a HideWhen of a shared view action button. This portion of the view is not stored on the server; it is only generated when a user opens a view.

For selection formulas, you cannot use @UserName because the view is generated by the server and the server is the user. Use Private On First Use if you have to make view selections dependent on the user name; private views are stored in the user's desktop.dsk file.


How do you sum number fields which have not been edited and initialized?

There are a few approaches to this problem. All of them include testing the value of each number field before summing the total:

mtotal := @If(field1 = ""; 0; field1) + @If(field2 = ""; 0; field2) +...;

Or in the input translation of each field you can do this:

@If(@IsNumber(FIELDNAME); FIELDNAME; 0)


Can you work around some of the size limitations in LotusScript programs?

The 32/64k limit applies to all events within an object. An object is anything with its own events. Buttons, forms, fields, and agents are all separate objects and have their own 32/64k limits.

For example, if you have code in the QueryOpen, PostOpen and QuerySave events within one form, all these count toward the form's 32/64k limit because they are all events for the form object.

Since there is no way to do a design synopsis which includes script, there is no easy way to figure out if you are at or near the limit. The only thing you can do is copy all the script from all the events for a particular object into a text file and then look at the size of the text file. This should APPROXIMATE the amount of compiled code (this is not a precise measure however).

There are several possible ways to work around the problem depending on where you are running into the limit.

1) Put the script in an text file and use the LotusScript %include command to load it. This script is not counted toward the memory limit. This is definitely the best workaround.

2) Put pieces of the script in entering events of hidden fields and use the LotusScript GotoField method to trigger the scripts.

3) Put additional scripts in subform events and embed the subforms in the form running into the memory limit. For example, if you're running out of space in the form object and wish to place more script in the PostOpen event, create a subform, place the desired code in its PostOpen event and insert the subform into the form.


How do you synchronize fields between documents created with two different forms?

In the 1st form, named "FORM1", create a computed field named FORM1_DocID. The FORM1_DocID field should be computed when composed and have this for the formula:

  @Text(@DocumentUniqueID)

For the documents created by the 2nd form, named "FORM2", you have to inherit and reference this FORM1_DocID value. To push information from Form2 to the document related by FORM1_DocID, you can put this your "Save & Exit" button of FOMR2:

  @SetDocField(FORM1_DocID;"form1_field1";form2_field1);
  @SetDocField(FORM1_DocID;"form1_field2";form2_field2);
  ...
  @Command([FileSave]);
  @Command([FileCloseWindow])


How do you automatically format phone numbers?

From andrew.olenick@prudential.com:

Use this code in the Exiting telephone field event. The user types in i.e. 2153339865 and the code formats the number.

Sub Exiting(Source As Field)
  On Error Goto err_SOLPhoneExit
  Dim workspace As New NotesUIWorkspace
  Set doc = workspace.CurrentDocument
  SOLPhone = doc.FieldGetText("telephone")

  ' If SOLPhone is null or like (123) 456-7890 then exit
  If SOLPhone = ""  Or SOLPhone Like  "([0-9][0-9][0-9]) [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]" Then
    Exit Sub
   ' If SOLPhone is 10 positions  and numeric, insert dashes and enter into SOLPhone field
  Elseif Len(SOLPhone) = 10  And Isnumeric(SOLPhone)  Then
    tSOLPhone = "(" + Left(SOLPhone,3) + ") " + Left(Right(SOLPhone,7),3) + "-" + Right(SOLPhone,4)
    Call doc.FieldSetText("telephone",tSOLPhone)
    Exit Sub
  Else
  ' if SOLPhone in error, give message
    Dim answer As Integer
    tSOLPhone = SOLPhone
    answer = Messagebox ("Enter the area code, exchange, and extension without the punctuation.  The  Phone # will be automatically formatted in (123) 456-7890 format.  Please try again.", MB_OK, "SOLPhone Incorrect")
    Call doc.FieldSetText("telephone",tSOLPhone)
    Call doc.GOTOFIELD("telephone")
    Exit Sub
  End If
err_SOLPhoneExit:
  Messagebox "Error " & Err() & ": " & Error()
  Exit Sub
End Sub

How do you select only Response documents in a view?

Turn off Show Response Hierarchy in your view properties and then and use this as your view selection formula:

  SELECT @IsAvailable($REF)

You can also do it using:

  Select @IsResponseDoc

or by selecting the names of the response forms like so:

  Select Form =
"the name of your response document you want to show"
& form =
"Another form that is a response document"


How do you validate a credit card number?

This LotusScript function will validate the checksum of a credit card number:

Function ValidateCC( strCC As String ) As Integer
  'Credit card validation algorithm
  'By Mark Dixon, Ives Development
  'Derived from http://prope.insa-lyon.fr/~fcoppola/credit.html
  'Parameter: strCC
  ' A string containing the card number to be validated.
  ' May contain non-numeric characters, e.g. spaces or dashes
  'Return value:
  ' True if the card number is good, False if the number is bad

  Dim nCheckSum As Integer
  Dim fDbl As Integer
  Dim nCharPos As Integer
  Dim nChar As Integer

  fDbl = False
  nCheckSum = 0

  'Read the card number from right to left
  For nCharPos = Len( strCC ) To 1 Step -1
    nChar = Asc( Mid( strCC, nCharPos, 1 ) ) - Asc( "0" )
    'Only process if the current character is a digit
    If 0 <= nChar And nChar <= 9 Then
      If ( fDbl ) Then
        nChar = nChar * 2
        If 10 <= nChar Then
          nChar = nChar - 9
        End If
      End If
      nCheckSum = nCheckSum + nChar
      fdbl = Not fdbl
    End If
  Next

  If nCheckSum Mod 10 = 0 Then ValidateCC = True Else ValidateCC = False
End Function


Can you make a popup calendar in Notes?

Put the following into text field and it will generate a calendar in your form. Make sure that the text area uses a fixed width font.

REM "Controllable spacing version from MStevenson@symantec.com";

TmpDate := @Date(@Today);

REM "HSP controls the horizontal size of the calendar.";
REM "Use 1 space for a really small calendar.";
REM "Default is 2 spaces.";
hsp := "  ";

REM "VSP controls the vertical size of the calendar";
REM "Default is 1 @Newline";
vsp := @Newline;

REM "DSP is used for the day headings";
dsp := hsp + " ";

REM "-------------------------- Calculate the days for this month";
A := @Adjust(TmpDate; 0; 0; -(@Day(TmpDate) - 1); 0; 0; 0);
A1 := @Weekday(A);
A2 := A;
A3 := @Month(A);
C1 := @Adjust(A2; 0; 0; (1 - A1); 0; 0; 0);
C2 := @Adjust(A2; 0; 0; (2 - A1); 0; 0; 0);
C3 := @Adjust(A2; 0; 0; (3 - A1); 0; 0; 0);
C4 := @Adjust(A2; 0; 0; (4 - A1); 0; 0; 0);
C5 := @Adjust(A2; 0; 0; (5 - A1); 0; 0; 0);
C6 := @Adjust(A2; 0; 0; (6 - A1); 0; 0; 0);
C7 := @Adjust(A2; 0; 0; (7 - A1); 0; 0; 0);
C8 := @Adjust(A2; 0; 0; (8 - A1); 0; 0; 0);
C9 := @Adjust(A2; 0; 0; (9 - A1); 0; 0; 0);
C10 := @Adjust(A2; 0; 0; (10 - A1); 0; 0; 0);
C11 := @Adjust(A2; 0; 0; (11 - A1); 0; 0; 0);
C12 := @Adjust(A2; 0; 0; (12 - A1); 0; 0; 0);
C13 := @Adjust(A2; 0; 0; (13 - A1); 0; 0; 0);
C14 := @Adjust(A2; 0; 0; (14 - A1); 0; 0; 0);
C15 := @Adjust(A2; 0; 0; (15 - A1); 0; 0; 0);
C16 := @Adjust(A2; 0; 0; (16 - A1); 0; 0; 0);
C17 := @Adjust(A2; 0; 0; (17 - A1); 0; 0; 0);
C18 := @Adjust(A2; 0; 0; (18 - A1); 0; 0; 0);
C19 := @Adjust(A2; 0; 0; (19 - A1); 0; 0; 0);
C20 := @Adjust(A2; 0; 0; (20 - A1); 0; 0; 0);
C21 := @Adjust(A2; 0; 0; (21 - A1); 0; 0; 0);
C22 := @Adjust(A2; 0; 0; (22 - A1); 0; 0; 0);
C23 := @Adjust(A2; 0; 0; (23 - A1); 0; 0; 0);
C24 := @Adjust(A2; 0; 0; (24 - A1); 0; 0; 0);
C25 := @Adjust(A2; 0; 0; (25 - A1); 0; 0; 0);
C26 := @Adjust(A2; 0; 0; (26 - A1); 0; 0; 0);
C27 := @Adjust(A2; 0; 0; (27 - A1); 0; 0; 0);
C28 := @Adjust(A2; 0; 0; (28 - A1); 0; 0; 0);
C29 := @Adjust(A2; 0; 0; (29 - A1); 0; 0; 0);
C30 := @Adjust(A2; 0; 0; (30 - A1); 0; 0; 0);
C31 := @Adjust(A2; 0; 0; (31 - A1); 0; 0; 0);
C32 := @Adjust(A2; 0; 0; (32 - A1); 0; 0; 0);
C33 := @Adjust(A2; 0; 0; (33 - A1); 0; 0; 0);
C34 := @Adjust(A2; 0; 0; (34 - A1); 0; 0; 0);
C35 := @Adjust(A2; 0; 0; (35 - A1); 0; 0; 0);
C36 := @Adjust(A2; 0; 0; (36 - A1); 0; 0; 0);
C37 := @Adjust(A2; 0; 0; (37 - A1); 0; 0; 0);

REM "----------------------------------- Create display values";
B1 := @If(@Month(C1) != A3; "  "; @Right("0" + @Text(@Day(C1)); 2));
B2 := @If(@Month(C2) != A3; "  "; @Right("0" + @Text(@Day(C2)); 2));
B3 := @If(@Month(C3) != A3; "  "; @Right("0" + @Text(@Day(C3)); 2));
B4 := @If(@Month(C4) != A3; "  "; @Right("0" + @Text(@Day(C4)); 2));
B5 := @If(@Month(C5) != A3; "  "; @Right("0" + @Text(@Day(C5)); 2));
B6 := @If(@Month(C6) != A3; "  "; @Right("0" + @Text(@Day(C6)); 2));

REM "These days always have values, so do not bother with the extra check";
B7 :=  @Right("0" + @Text(@Day(C7)); 2);
B8 := @Right("0" + @Text(@Day(C8)); 2);
B9 := @Right("0" + @Text(@Day(C9)); 2);
B10 := @Right("0" + @Text(@Day(C10)); 2);
B11 := @Right("0" + @Text(@Day(C11)); 2);
B12 := @Right("0" + @Text(@Day(C12)); 2);
B13 := @Right("0" + @Text(@Day(C13)); 2);
B14 := @Right("0" + @Text(@Day(C14)); 2);
B15 := @Right("0" + @Text(@Day(C15)); 2);
B16 := @Right("0" + @Text(@Day(C16)); 2);
B17 := @Right("0" + @Text(@Day(C17)); 2);
B18 := @Right("0" + @Text(@Day(C18)); 2);
B19 := @Right("0" + @Text(@Day(C19)); 2);
B20 := @Right("0" + @Text(@Day(C20)); 2);
B21 := @Right("0" + @Text(@Day(C21)); 2);
B22 := @Right("0" + @Text(@Day(C22)); 2);
B23 := @Right("0" + @Text(@Day(C23)); 2);
B24 := @Right("0" + @Text(@Day(C24)); 2);
B25 := @Right("0" + @Text(@Day(C25)); 2);
B26 := @Right("0" + @Text(@Day(C26)); 2);
B27 := @Right("0" + @Text(@Day(C27)); 2);
B28 := @Right("0" + @Text(@Day(C28)); 2);
B29 := @Right("0" + @Text(@Day(C29)); 2);

B30 := @If(@Month(C30) != A3; "  "; @Right("0" + @Text(@Day(C30)); 2));
B31 := @If(@Month(C31) != A3; "  "; @Right("0" + @Text(@Day(C31)); 2));
B32 := @If(@Month(C32) != A3; "  "; @Right("0" + @Text(@Day(C32)); 2));
B33 := @If(@Month(C33) != A3; "  "; @Right("0" + @Text(@Day(C33)); 2));
B34 := @If(@Month(C34) != A3; "  "; @Right("0" + @Text(@Day(C34)); 2));
B35 := @If(@Month(C35) != A3; "  "; @Right("0" + @Text(@Day(C35)); 2));
B36 := @If(@Month(C36) != A3; "  "; @Right("0" + @Text(@Day(C36)); 2));
B37 := @If(@Month(C37) != A3; "  "; @Right("0" + @Text(@Day(C37)); 2));

ShowMonth := @Select(@Month(A2); "January"; "February";
 "March"; "April"; "May"; "June"; "July"; "August";
 "September"; "October"; "November"; "December");

REM "---------------------- Display the calendar";
sp + sp + sp + ShowMonth + " " + @Text(@Day(TmpDate)) + ", " + @Text(@Year(A2)) + vsp +

" " + "S" + dsp + "M" + dsp + "T" + dsp + "W" + dsp + "T" + dsp + "F" + dsp + "S" + vsp +
B1 + hsp + B2 + hsp + B3 + hsp + B4 + hsp + B5 + hsp + B6 + hsp + B7 + vsp +
B8 + hsp + B9 + hsp + B10 + hsp + B11 + hsp + B12 + hsp + B13 + hsp + B14 + vsp +
B15 + hsp + B16 + hsp + B17 + hsp + B18 + hsp + B19 + hsp + B20 + hsp + B21 + vsp +
B22 + hsp + B23 + hsp + B24 + hsp + B25 + hsp + B26 + hsp + B27 + hsp + B28 + hsp + vsp +
B29 + hsp + B30 + hsp + B31 + hsp + B32 + hsp + B33 + hsp + B34 + hsp + B35 + hsp + vsp +
B36 + hsp + B37


How do you get the current access level of a user?

Dim s As New notessession
Dim db As notesdatabase

Set db = s.CurrentDatabase
Set level% = db.CurrentAccessLevel

This will return a value ranging from 0 to 6 (0 = No Access, 6 = Manager, all other levels in between).


Can you open a view in full screen mode from a Navigator?

For the navigator hotspot action, select Formula and use this:

@Command([OpenView]; "Your View here...");
@Command([ViewNavigatorsNone])


How do you generate a subset of list values based on the contents of another list?

This is useful for getting a subset of roles based on what state a document's workflow is in.

REM "From Damien Katz @ Unity Consulting"
tList1 :=tList1;
tList2 := tList2;
tItemsToKeep :=tItemsToKeep;
REM "Set variable tList1 to the list of values you want scan.";
REM "Set variable tList2 to corresponding list of values that you want to keep.";
REM "Set tItemsToKeep to the values you want ton scan list1 for.";
REM "tFilteredList returns the values from List2 that are kept";

REM "**************************Begin Function";
tListLength := @Elements( tList2);

tDigits := "0" : "1" : "2" : "3" : "4" : "5" : "6" : "7" : "8" : "9";

tNumbers :=  @Subset( @If( tListLength  <= 10; tDigits; tListLength >= 100;  tDigits *+ tDigits; tDigits *+ tDigits *+ tDigits); tListLength ) + "$$";

tMixedListWithNumbers := @Replace( tNumbers *+ tItemsToKeep ; tNumbers + tList1; tNumbers + tList2);
tMixedListWithoutNumbers := @Right( tMixedListWithNumbers; "$$");
tFilteredList := @Trim( @Replace( tMixedListWithoutNumbers ; tItemsToKeep ; ""));
REM "**************************End Function";


How do you keep a running history of all entries in an RTF field?

Put this script in the QueryClose event of the document. It will append the RTF field named Details to an RTF field named Details_History:

FIELD Details:
Rich Text, Editable
Hide when previewed for reading, opened for reading, printed

FIELD Details_History:
Rich Text, Computed
never hide


Sub Queryclose(Source As Notesuidocument, Continue As Variant)
 On Error Goto Oops

 Dim session As New NotesSession
 Dim doc As NotesDocument
  Set doc = session.CurrentDatabase.GetDocumentByUNID(Source.Document.UniversalID)
 Dim vDetails As Variant
  Set vDetails = doc.GetFirstItem("Details")
 Dim vHistory As Variant
  Set vHistory = doc.GetFirstItem("Details_History")

  If (vDetails.Type = RICHTEXT And vHistory.Type = RICHTEXT) Then
    Call vHistory.AppendText(Format$(Now, "mm/dd/yy hh:nn AM/PM") & " by " & session.CommonUserName & ":  ")
    Call vHistory.AppendRTItem(vDetails)
    Call vHistory.AddNewLine(2)
    Call vDetails.Remove
    Call doc.Save(True, False)
  End If

TheEnd:
  Continue = True
Exit Sub

Oops:
  Resume TheEnd
End Sub


Can you use @Functions in LotusScript?

You can use the LotusScript Evaluate function. For example, this gets the common name portion of a hierarchical user name:

  Dim szCommonName As String
  Dim result As Variant
  result = Evaluate("@Name([CN]; @Username)")
  szCommonName = result(0)


Can you use views from the Mail template in your own databases?

There are two useful design elements from the mail template that can be used in your Notes databases:

"All Documents" is a view. Create this by creating a new view named ($All) that HAS to be a shared view. It will automatically name itself "All Documents" and you can change the design to suit your needs. If will also have an icon of several little sheets of paper and appear above the private and shared views and folders.

"Trash" is a folder. Create this by creating a new folder named ($Trash) that also HAS to be a shared folder. It will appear under the "All Documents" view and have the look of little trash can. A suggestion would be to make this folder NOT Show response documents in hierarchy so that you can drag response documents into the trash without having to drag its parent document. Now design it how ever you like. Users can drag to the trash can, exit the database without deleting the documents and have them in the trash can when they come back into the database.


How do you compare date/time fields using Lotuscript?

This example will compare two date fields in document:

mdate1V = document.DateField1(0)
mdate2V = document.DateField2(0)
If mdate1V < mdate2V Then
  MsgBox "DATE 1 LESS THEN DATE 2"
Else
  MsgBox "DATE 2 LESS THEN OR EQUAL TO DATE 1)
End If

How do you go to the last document in a category using Lotuscript?

You can also use the routine below to move onto the next category by moving to the last document in a specified category, then using view.GetNextDocument to move to the next category. Call the routine below as follows:

notesBackendDoc = GoToLastDocInCategory(StartDoc, View, FieldName, CategoryValue)

where:
StartDoc
- a NotesDocument in the category that you want to start out the search from.
View
- a NotesView that you will be searching.
FieldName
- a String containing the name of the item that holds the Category value.
CategoryValue
- a String containing what category value to check for.

Function GoToLastDocInCategory(StartDoc As NotesDocument, CheckView As
NotesView, ItemName As String, CategoryValue As String) As NotesDocument
  Dim PreviousDoc As NotesDocument
  Dim NextDoc As NotesDocument
  Dim CategoryItem As NotesItem
  Dim ThisDocCategoryValue As String
  Set NextDoc = StartDoc
  Set PreviousDoc = StartDoc
  Set CategoryItem = StartDoc.GetFirstItem(ItemName)
  ThisDocCategoryValue = CategoryItem.Text
  Do While Not(NextDoc Is Nothing) And (CategoryValue = ThisDocCategoryValue)
    Set PreviousDoc = NextDoc
    Set NextDoc = CheckView.GetNextDocument(NextDoc)
    If NextDoc Is Nothing Then Exit Do
    Set CategoryItem = NextDoc.GetFirstItem(ItemName)
    ThisDocCategoryValue = CategoryItem.Text
  Loop
  Set GoToLastDocInCategory = PreviousDoc
End Function


How do you create mailing labels in Notes?

The Lotus Approach (and its close cousin, Notes Reporter) database program has built-in support for Avery labels.

You can also use LabelPro for Lotus Notes from a company called Thuridion who can be reached at (800)LPW-1806.

Label Maker from Cambridge Software Group
is another label maker program which is bundled with CoStar's LabelWriter printer. They can be reached at (800)792-7248.

Address Label Maker from IVES Technologies uses DDE on MS Word to generate labels.

Intelliprint from CSS can print labels from Notes views.

NotesToPaper by SoftVision Development.


What are the Unix syntaxes for calling DLLs from LotusScript?

For AIX: Declare Function name Lib "libnotes_r.a" Alias "alias" (arglist)
For Solaris: Declare Function name Lib "libnotes.so" Alias "alias" (arglist)
For HP/UX: Declare Function name Lib "libnotes.sl" Alias "alias" (arglist)


Can you dynamically select documents per user without using a ReaderNames field?

Use this for a view selection formula:
username := @Name([CN]; @UserName);
Select (Form = "OrderForm") & (@Contains(OrderOwner;username) = 1)
and set the View Properties so that the view index is discarded every time. This will select documents that use the form "OrderForm" and were created by the current user.


How do you display documents created with a form using a layout region?

Use LotusScript in the QueryOpenDocument Event of the view to do this:

Set the variable CONTINUE = FALSE to prevent the document from being displayed using the form.
Get the collection from the NotesUIView.Documents property (the NotesUIView is the SOURCE variable for the event). The first document in the collection is the one the user is trying to open.
Use the NotesUIWorkspace.DialogBox method to open this document.


Why doesn't NotesUIDocument.GetFieldText return the alias for a keyword selection?

The NotesUIDocument class is designed to work with the interface elements (what is being displayed) of a document. Because of this, the value you retrieve from a field is what is being displayed to a user.
If you are designing a new form, a workaround you can use is to make the aliases numerical such as:

  Draft | 1
  Submitted | 2
  Comment | 3

Then, you can handle each case using this code (if the keyword field is named "Status"):
  Dim ws As New NotesUIWorkspace
  Dim doc As NotesDocument
  Dim uidoc As NotesUIDocument
  Dim desiredresult As Variant
  Set uidoc = ws.CurrentDocument
  Set doc = uidoc.Document
  desiredresult = doc.GetItemValue("Status")
  Select Case desiredresult(0)
  Case "1"
       ...
  Case "2"
       ...
  Case Else
       ...
  End Select

Why doesn't my "If documents have been created or modified" agent execute immediately?

The agent manager task only executes every 30 minutes by default. This is why the "when created/modified" agent runs every 30 minutes. You can change these two lines in your notes.ini file to decrease the delay between runs of the agent manager:

  AMgr_DocUpdateAgentMinInterval=value in minutes(default is 30)
  Amgr_DocUpdateEventDelay= value in minutes (default is 5)

The lowest values recommended for these two values are 5 and 2, respectively.


How do you insert a new line in a Rich Text field using a macro?

@Command([EditInsertText]; @Char(0))

Instead of using @Char(0), you can also use @Newline.


How do you set the server to run agents on with a hidden database design?

Add a configure button to the application's UI. You can use these @Commands in the button

  @Command([AgentSetServerName];"AgentName");  // prompts for server name
  @Command([AgentEnableDisable];"AgentName"; "1");

Alternately, you could have a second unhidden database which just has agents which call agents within the hidden database. This technique lets the user set the schedule for the other agents. Here is code that will run an agent in another database:

Sub Initialize
  Dim db As New NotesDatabase("", "")
  Dim Agent As NotesAgent
  If (db.open("", "hiddenDB.nsf")) Then
    Set Agent = db.GetAgent("(Check Servers For Response)")
    If Not(Agent Is Nothing) Then
      Call Agent.Run
    Else
      Msgbox "Agent not found..."
    End If
  End If
End Sub


How do you sort a document collection?

Here is an example that does a bubble sort on the document collection using two fields as the sort key:

Sub Swap(doc1 As NotesDocument ,doc2 As NotesDocument)
 Dim d As NotesDocument
 Set d = doc1
 Set doc1 = doc2
 Set doc2 = d     
End Sub

Sub CollectionToSortedArray(col As NotesDocumentCollection, docs() As NotesDocument)     
 Dim i As Integer
 Dim doc As NotesDocument
 Dim n As Integer, sorted As Integer
 Dim s1, s2 As String
     
 n = col.count
 Redim docs(n) As NotesDocument
 ' push to array
 For i = 0 To n - 1
   Set docs(i) = col.GetNthDocument(i+1)
 Next
     
 'bubble sort array
 sorted = False
 Do While (sorted = False)          
   sorted = True
   For i = 0 To n - 2
     ' sort based on QuoteNo and ItemNo fields
     s1 = docs(i).QuoteNo(0) & docs(i).ItemNo(0)
     s2 = docs(i+1).QuoteNo(0) & docs(i+1).ItemNo(0)
     If(Strcomp(s1, s2, 5) = 1) Then  'No Pitch, No Case Compare
       Call Swap(docs(i),docs(i+1))
       sorted = False
     End If
   Next
 Loop
End Sub


Here's another sample using a Merge Sort which is faster for large collections:

Sub qsort(element, sortkeys)
  ' To be called by REFERENCE
  Call mergesort(element, sortkeys, Lbound(sortkeys), Ubound(sortkeys), False)
End Sub

Sub mergesort(element, sortkeys, l As Integer, r As Integer, isclass As Variant)
  ' From Paul Hudson (paulh@harlequin.co.uk)
  ' Called by qsort, but can be used on its own
  Dim i As Integer, j As Integer, k As Integer, m As Integer
  Dim b1(), b2()

  If (r - l > 0) Then
    m = (r + l) \ 2
    Call mergesort(element, sortkeys, l, m, isclass)
    Call mergesort(element, sortkeys, m + 1, r, isclass)
    Redim b1(l To r)
    Redim b2(l To r)
    For i = l To m
      If isclass Then
        Set b1(i) = element(i)
      Else
        b1(i) = element(i)
      End If
      b2(i) = sortkeys(i)
    Next
    For j = m+1 To r
      If isclass Then
        Set b1(r + m + 1 - j) = element(j)
      Else
        b1(r + m + 1 - j) = element(j)
      End If
        b2(r + m + 1 - j) = sortkeys(j)
    Next
    i = l
    j = r
    For k = l To r
      If b2(i) < b2(j) Then
        If isclass Then
          Set element(k) = b1(i)
        Else
          element(k) = b1(i)
        End If
        sortkeys(k) = b2(i)
        i = i + 1
      Else
        If isclass Then
          Set element(k) = b1(j)
        Else
          element(k) = b1(j)
        End If
        sortkeys(k) = b2(j)
        j = j - 1
      End If
    Next
  End If
End Sub


What HelpDesk products are available for Notes?

* Visual Help Desk - Brainstorm Technologies, (617)588-0800
* Sentinel Help Desk - MayFlower Consulting, (617)270-9000
* Help Desk Management - QXCOM,(818)991-8700
* Groupsoft Help Desk for Domino - GroupSoft Systems, (617)928-1339
* Enhaced Help Desk R4 - Techflow, Inc.
* Help! - GWI Software, (360)693-6944


How do you force a user to use a button to save a form?

This code satisfies three requirements:
1) prevent users from saving a form via menu or keyboard controls; only the action button can be used for saves
2) only use ONE field to accomplish to keep application overhead down
3) depending on a value in a status field, action button should issue file save or file save new version

AllowSave field: Editable, Text, Hidden

  Default value = "0"
  Validation = @If(AllowSave = "0"; @Failure(...); @Success)

Action Button:

  FIELD AllowSave := "1";
  @If(Status = "Open";
    @PostedCommand([FileSaveNewVersion]);
    @PostedCommand([FileSave])
  )

Form PostOpen Event:

  FIELD AllowSave := "0";
  @SetField("AllowSave"; "0")


Can you start a program in Notes and wait for it to finish?

Yes, you can use this LotusScript code to do so:

Public Type STARTUPINFO
  cb As Long
  lpReserved As String
  lpDesktop As String
  lpTitle As String
  dwX As Long
  dwY As Long
  dwXSize As Long
  dwYSize As Long
  dwXCountChars As Long
  dwYCountChars As Long
  dwFillAttribute As Long
  dwFlags As Long
  wShowWindow As Integer
  cbReserved2 As Integer
  lpReserved2 As Long
  hStdInput As Long
  hStdOutput As Long
  hStdError As Long
End Type

Public Type PROCESS_INFORMATION
  hProcess As Long
  hThread As Long
  dwProcessID As Long
  dwThreadID As Long
End Type

Declare Function WaitForSingleObject Lib "kernel32" (Byval _
  hHandle As Long, Byval dwMilliseconds As Long) As Long

Declare Function CreateProcessA Lib "kernel32" (Byval _
  lpApplicationName As Long, Byval lpCommandLine As String, Byval _
  lpProcessAttributes As Long, Byval lpThreadAttributes As Long, _
  Byval bInheritHandles As Long, Byval dwCreationFlags As Long, _
  Byval lpEnvironment As Long, Byval lpCurrentDirectory As Long, _
  lpStartupInfo As STARTUPINFO, lpProcessInformation As _
  PROCESS_INFORMATION) As Long

Declare Function CloseHandle Lib "kernel32" (Byval _
  hObject As Long) As Long

Public Const NORMAL_PRIORITY_CLASS = &H20&
Public Const INFINITE = -1&

Public Sub ShellAndWait(Byval RunProg As String)
  ' From Kevin Pauli (kcpauli@usa.net)
  Dim RetVal As Long
  Dim proc As PROCESS_INFORMATION
  Dim StartInf As STARTUPINFO
  StartInf.cb = Len(StartInf)
  'Execute the given path
  RetVal = CreateProcessA(0&, RunProg, 0&, 0&, 1&, _
  NORMAL_PRIORITY_CLASS, 0&, 0&, StartInf, proc)

  'Disable this app until the shelled one is done
  RetVal = WaitForSingleObject(proc.hProcess, INFINITE)
  RetVal = CloseHandle(proc.hProcess)
End Sub

However, note that it is only for Win32 systems. The concept would be the same for other operating systems.


How do you access a specific element of a multi-value field?

To extract element 'n' from the field "Choices":

  @Subset(@Subset(Choices;n); -1)


How do you find out what Roles a user has in the current database?

This function will give you a list of all roles a user is in, even if the user is in nested groups which are listed in the ACL.

' Roles(UserName$) :
'        It checks for roles of UserName$ (could be both abbreviate or hierarchical) in current database
'        If no exact ACL found it checks all group recursively
'        If UserName$ is member of two or more groups it returns the roles of all of them
'        If nothing found, it returns "-Default-" roles
'        It doesn't check duplicate roles (but this is not a problem)
'    Return value: array of roles (strings)
'
' IsaMemberOf(UserName$, GroupName$) :
'        Check if UserName$ is a member of GroupName$
'        It searchs group recursively
'        It searchs first public address book
'    Return value: boolean
'
' NameSimple$(Name$) :
'        Just acts like formula @Name( [Abbreviate]  ; Name )
'    Return value: string
'
' Marco Beri
' marcob@equalis.it

Function Roles(UserName$) As Variant
  Dim AllRoles As Variant
  Dim session As New NotesSession
  Dim db As NotesDatabase
  Dim acl As NotesACL
  Dim entry As NotesACLEntry
  Dim FirstGroupFound%

  Set db = session.CurrentDatabase
  Set acl = db.ACL
  Set entry = acl.GetEntry( UserName$ )
  If entry Is Nothing Then
    Set entry = acl.GetEntry( NameSimple$(UserName$) )
  End If
  If Not entry Is Nothing Then
    AllRoles = entry.Roles
  Else
    Set entry = acl.GetFirstEntry
    Do While Not entry Is Nothing
      'Default roles (survives only if no other found)
      If Trim$(Ucase$(entry.name)) = Ucase$("-Default-") Then
        AllRoles = entry.roles
      Else
        If IsaMemberOf(UserName$, entry.name) Then
          If FirstGroupFound% Then
            Redim Preserve AllRoles(Ubound(AllRoles)+Ubound(entry.roles)+1)
            For Cont%=0 To Ubound(entry.roles)
              AllRoles(Ubound(AllRoles)-Cont%) = entry.roles(Cont%)
            Next
          Else
            FirstGroupFound% =True
            AllRoles=entry.roles
          End If
        End If
      End If
    Set entry = acl.GetNextEntry( entry )
    Loop
  End If
  Roles = AllRoles
End Function

Function IsaMemberOf(UserName$, GroupName$)
  On Error Goto IsaMemberOfError

  Dim doc As NotesDocument
  Static ViewGroup As NotesView

  If (ViewGroup Is Nothing) Then
    Dim PublicBook As Variant
    Dim session As New NotesSession

    Set PublicBook=Nothing
    Forall Book In session.AddressBooks
      If (Book.IsPublicAddressBook) Then
        Set PublicBook=Book
        Exit Forall
      End If
    End Forall
    If PublicBook Is Nothing Then
      Forall Book In session.AddressBooks
        Set PublicBook=Book
        Exit Forall
      End Forall
    End If
    If Not (PublicBook Is Nothing) Then
      Call PublicBook.Open("", "")
      Set ViewGroup=PublicBook.GetView("Groups")
      If ViewGroup Is Nothing Then
        Messagebox "No group view found"
      End If
    Else
      Messagebox "No address book found"
      Exit Function
    End If
  End If

  Set doc=ViewGroup.GetDocumentByKey(GroupName$)
  If doc Is Nothing Then
    IsaMemberOf = False
  Else
    If Not (doc Is Nothing) Then
      Forall Member In doc.Members
        If Trim$(Ucase$(Member)) = Trim$(Ucase$(UserName$)) Or Trim$(Ucase$(Member)) = Trim$(Ucase$(NameSimple(UserName$))) Then
          IsaMemberOf = True
          Exit Forall
        Else
          If IsaMemberOf(UserName$, Cstr(Member)) Then
            IsaMemberOf = True
            Exit Forall
          End If
        End If
      End Forall
    End If
  End If

Exit Function

IsaMemberOfError:
  Messagebox "IsaMemberOf"+Str$(Err)+": "+Error$
  Exit Function
End Function

Function NameSimple$(Byval NameToConvert$)
  Dim InstrUguale%,Cont%,NameResto$
  Do
    InstrUguale%=Instr(NameToConvert$,"=")
    If InstrUguale%=0 Then
      Exit Do
    End If
    NameResto$=Mid$(NameToConvert$,InstrUguale%+1)
    For Cont%=InstrUguale%-1 To 0 Step -1
      If Cont%=0 Then
        NameToConvert$=""
      Elseif Mid$(NameToConvert$,Cont%,1)="/" Then
        NameToConvert$=Left$(NameToConvert$,Cont%)
        Exit For
      End If
    Next
    NameToConvert$=NameToConvert$+NameResto$
  Loop
  NameSimple$=NameToConvert$
End Function


An alternative way of doing this is to use the Evaluate of doing this (providing you aren't using early versions of Notes 4.x which leaked memory each time Evaluate was called):

  Dim UserRoles As Variant
  UserRoles = Evaluate("@UserRoles")

How do your control an OLE-VBA object in LotusScript?

This code uses the OLE support in the Win32 version of Notes to set the A1 cell in the Sheet1 worksheet to a value from Field1 in the current document:

  Set obj = CreateObject("Excel.Application")
  obj.Workbooks.Open "c:\test.xls"
  value = doc.GetItemValue("Field")(0)
  obj.Worksheets("Sheet1").Range("A1").value = value


How do you add a response's doclink to a parent document?

Assuming you have a way to get to the response document, or you are already in the response document, try this:

Sub PlaceDocLinkInParent (rdoc As NotesDocument)
REM "NOTE" rdoc is supposed to be the response document that you want the 
REM Doc Link for.  As I said above, I will assume you have obtained this and
REM just need to call this procedure to place the doc link.

Dim sess As New NotesSession
Dim db As NotesDatabase
Dim pdoc As NotesDocument
Dim m_unid As String
Dim rt As NotesRichTextItem
Set db = sess.CurrentDatabase
m_unid$ = rdoc.ParentDocumentUNID
Set pdoc = db.GetDocumentByUNID(m_unid$)
Set rt = New NotesRichTextItem(pdoc, "DocLinkField")
Call rt.AppendDocLink(rdoc, "Link To Reponse Document")
Call pdoc.Save(True, False)
End Sub

Basically, this script gets the parent unid from the response, then gets the parent document with the GetDocumentByUNID method, creates a new rich text field in the parent and places a doc link in it.


How do you track who changed a critical field?

If you want to add an audit trail of the modifications made to a critical field named "PRIORITY" it can be done with the following:
1) Create a duplicate "PRIORITY" field (named "PRIORITYDelta") that is hidden and has in its input translation formula a statement to store the contents of the PRIORITY field. This will retain the contents of the priority field before editing in a current session.
2) Create a multi-value field ("Updatesto") with a formula that compares PRIORITY to PRIORITYDelta when the document is being saved and when the condition is right (i.e. PRIORITY != PRIORITYDelta) attaches the new save information to the field:

feed := @Name([CN]; @V3UserName) + " on " + @Text(@Date(@Now)) + " at " + @Text(@Time(@Now)) + "     " +  PRIORITY;
FIELD Updatesto := @If(@IsDocBeingSaved & PRIORITY != PRIORITYDelta ; Updatesto : feed; Updatesto);
Updatesto

Note that the Revision field (Updatesto) needs to before PRIORITYDelta Field on the form for the revision field to keep a change history.


How do you find the exact version number of Notes?

The following converts the version number, including lettered versions, to dotted decimal format for easy comparison. 4.6.3b becomes version 4.6302, which is definitely a "higher" version than 4.6.2a (4.6201 in this code).

' from Scott Purl (spurl@acm.org)
' Yep.  Only one Dim.  Session.NotesVersion holds the key.
Dim Session As New NotesSession

' Find out the version information
MyVersion = Session.NotesVersion
' Get the length of the version string
Length = Len(MyVersion)
' Discover What the "half" delimiter is, meaning what's the first non-alphanumeric character starting from the left
' Note that in the North American and International versions, this first non-alpha character differs
If MyVersion Like "*Intl*" Then
   SepChar = "("
   OffSet = 0
Else
   SepChar = "|"
   OffSet = 2
End If
' Now find this first non-alphanumeric character
SepLoc = Instr(MyVersion, SepChar)
' Get everything to the left of that character
LeftHalf = Left(MyVersion, SepLoc - 1)
' Find the only space in the left half
SpacLoc = Instr(LeftHalf, " ")
' The version number is what's left to the right of the space in the left half, minus extra spaces
' code (with bug) was VerNum = Trim(Right(LeftHalf, SpacLoc - OffSet))
VerNum = Trim(Right(LeftHalf,  Len(LeftHalf) - SpacLoc - OffSet))
' Get the length of the version number
VerLen = Len(VerNum)
' Loop through the version number to remove periods
For x =1 To VerLen
CurChar = Mid(VerNum, x, 1)
If CurChar = "." Then
   ' Do Nothing
Else
   ' Keep appending non-period characters until finished
   SubVer = SubVer & CurChar
End If
Next

' If the right-most character is a letter, convert it to a number
' "a" becomes "01", and "z" becomes "26"
RSubVer = Right(SubVer, 1)
If Instr("abcdefghijklmnopqrstuvwxyz", RSubVer) Then
   ' The first 9 letters of the alphabet need a padding leading zero
   If Instr("abcdefghi", RSubVer) Then
      AlphaNum = Instr("abcdefghi", RSubVer)
      NewSubVer = Left(SubVer, Len(SubVer) -1) & "0" & AlphaNum
   End If
   ' The rest of the alphabet are all greater than 10 in position
   If Instr("jklmnopqrstuvwxyz", RSubVer) Then
      AlphaNum = Instr("abcdefghijklmnopqrstuvwxyz", RSubVer)
      NewSubVer = Left(SubVer, Len(SubVer) -1) & AlphaNum
   End If
' And the numeric equivalent of the position is
SubVer = NewSubVer
End If

' Assemble it into leftmost character, plus a period, plus the rest of the iterated sub version
TextVer = Left(SubVer, 1) & "." & Right(SubVer, Len(Subver) -1)

' Convert it to a normal number so we can do quick comparisons.
FinVer = Cstr(TextVer)

You can then do:

If FinVer >= 4.6302 Then
  'Action if True
Else
  'Action if False
End If

Where can I get more information on Java access to Notes?

Go to Lotus Developer Central and search for "Java".


How do you put a popup calendar in a layout region?

In Notes 4.x, if you have a date field in a layout region, it will automatically have a calendar popup. In other fields or in Notes 3.x, you can also use a linkpopup text field.


How do you operate on the currently selected documents in LotusScript?

To determine the currently selected document in a view you have to traverse it with the NotesDatabase property:UnprocessedDocuments which returns a document collection that you can examine.
The ... part in the code below marks where you can put code to access the active document. This may look strange, but it actually only returns the document that you currently stand on (unless you have marked a set of documents).

  Dim workspace As New notesuiworkspace
  Dim uidoc As notesuidocument
  Dim session As New NotesSession
  Dim db As NotesDatabase
  Dim collection As NotesDocumentCollection
  Dim doc As NotesDocument
  Set db = session.CurrentDatabase
  Set collection = db.UnprocessedDocuments
  If (Not collection Is Nothing) Then
    For i = 1 To collection.Count
      Set doc = collection.GetNthDocument(i)
      ...
    Next
  End If


In what order do @Commands execute?

1) Declare variables.
2) Everything else except a few @Commands.
3) The few @Commands that are not in (2).

These are the commands in category (3):
FileCloseWindow
FileDatabaseDelete
FileExit
NavigateNext
NavigateNextMain
NavigateNextSelected
NavigateNextUnread
NavigatePrev
NavigatePrevMain
NavigatePrevSelected
NavigatePrevUnread
ToolsRunBackgroundMacros
ToolsRunMacro
ViewChange
ViewSwitchForm


How do you display progress to the user via LotusScript?

If you are processing a large collection of documents, it would be useful to show the user progress so they don't think your application has hung. Here is a method to show a progress meter in the status bar in Notes:

REM "From Erden Eruc @ NGSINC"

Dim i As Integer
Dim s As String
     
'Is this 100 meter dash? no it is a meter with 100 dashes :)
     
s = "--------------------------------------------"&_
"--------------------------------------------------------"
For i = 1 To 100
  s = Left( Chr(1) & s, 100 )
  If i<10 Then
    Print "Percent Done:    "& Str(i)&"% - " & s 
  Elseif i = 100 Then
    Print "Percent Done:"& Str(i)&"% - " & s
  Else
    Print "Percent Done:  "& Str(i)&"% - " & s
  End If
Next
Print "Percent Done: 100% - Job complete..."


For a Win32-specific version that uses Notes functions (note: this is a dangerous thing to do, but if you really must have a graphical progress bar..):
Const NPB_TWOLINE% = 1
Const NPB_STATUSBAR% = 32

Declare Function NEMProgressBegin Lib "nnotesws.dll" ( Byval wFlags As Integer ) As Long
Declare Sub NEMProgressDeltaPos Lib "nnotesws.dll" ( Byval hwnd As Long, Byval dwIncrement As Long )
Declare Sub NEMProgressEnd Lib "nnotesws.dll" ( Byval hwnd As Long )
Declare Sub NEMProgressSetBarPos Lib "nnotesws.dll" ( Byval hwnd As Long, Byval dwPos As Long)
Declare Sub NEMProgressSetBarRange Lib "nnotesws.dll" ( Byval hwnd As Long, Byval dwMax As Long )
Declare Sub NEMProgressSetText Lib "nnotesws.dll" ( Byval hwnd As Long, Byval pcszLine1 As String, Byval pcszLine2 As String )

' From Mark Dixon @ Ives

Dim hwnd As Long
Dim i As Long
Dim j As Long
     
'Create the progress bar
hwnd = NEMProgressBegin( NPB_TWOLINE )
     
'Set the bar range - the default is 100
NEMProgressSetBarRange hwnd, 200
     
'Display some text on the dialog.  The second line is ignored if NPB_TWOLINE not specified
NemProgressSetText hwnd, "Calculating..", "Start"
     
For i = 0 To 200
  'Simple delay loop to give us time to see whats going on
  For j = 0 To 5000     
  Next
  'Update the bar position - we could also use NEMProgressDeltaPos hwnd, 1 here
  NEMProgressSetBarPos hwnd, i 
  'Update the text at halfway
  If i = 100 Then
    NEMProgressSetText hwnd, "Calculating", "Half way"
  End If
Next

'Destroy the dialog when we're done
NEMProgressEnd hwnd


How do you convert a numerical value to the equivalent written text?
To convert a field called origNumber to written text, use the field formula:

REM "Thanks to MStevenson@symantec.com for updating this for negative numbers";

REM "Get numerical value";
origNumber := <numerical value>;

REM "Convert negative to positive";
NUMBER := @If(origNumber = "";0;origNumber < 0;-origNumber;origNumber);

REM "Test range";
@If(NUMBER > 999999999999999; @Return("Quadrillion Plus!"); "");

REM "Parse, format fixed with 2 decimals";
money := @Text(NUMBER; "F2");
c := @Word(money; "."; 2);
d := @Right("000000000000000" + @Word(money; "."; 1); 15);

REM "Constants";
n := "" : "One" : "Two" : "Three" : "Four" : "Five" : "Six" : "Seven" :
 "Eight" : "Nine" : "Ten" : "Eleven" : "Twelve" : "Thirteen" :
 "Fourteen" : "Fifteen" : "Sixteen" : "Seventeen" : "Eighteen" :
 "Nineteen";
m := "" : "" : "Twenty " : "Thirty " : "Forty " : "Fifty " : "Sixty " :
 "Seventy " : "Eighty " : "Ninety ";

REM "Ones";
d0 := @Middle(d; 12; 3);
h0 := @Subset(@Subset(n; @TextToNumber(@Left(d0; 1)) + 1); -1);
v0 := @TextToNumber(@Right(d0; 2));

t0 := @Trim(@If(h0 = ""; ""; h0 + " Hundred ") + @Subset(@Subset(m; 
 1 + @TextToNumber(@Middle(d0; 1; 1))); -1) + @Subset(@Subset(n;
 @If(v0 > 19; @TextToNumber(@Right(d0; 1)); v0) + 1); -1));

REM "Thousands";
d1 := @Middle(d; 9; 3);
h1 := @Subset(@Subset(n; @TextToNumber(@Left(d1; 1)) + 1); -1);
v1 := @TextToNumber(@Right(d1; 2));

t1 := @Trim(@If(h1 = ""; ""; h1 + " Hundred ") + @Subset(@Subset(m; 
 1 + @TextToNumber(@Middle(d1; 1; 1))); -1) + @Subset(@Subset(n; 
 @If(v1 > 19; @TextToNumber(@Right(d1; 1)); v1) + 1); -1));

REM "Millions";
d2 := @Middle(d; 6; 3);
h2 := @Subset(@Subset(n; @TextToNumber(@Left(d2; 1)) + 1); -1);
v2 := @TextToNumber(@Right(d2; 2));

 t2 := @Trim(@If(h2 = ""; ""; h2 + " Hundred ") + @Subset(@Subset(m; 
 1 + @TextToNumber(@Middle(d2; 1; 1))); -1) + @Subset(@Subset(n; 
 @If(v2 > 19; @TextToNumber(@Right(d2; 1)); v2) + 1); -1));

REM "Billions";
d3 := @Middle(d; 3; 3);
h3 := @Subset(@Subset(n; @TextToNumber(@Left(d3; 1)) + 1); -1);
v3 := @TextToNumber(@Right(d3; 2));

t3 := @Trim(@If(h3 = ""; ""; h3 + " Hundred ") + @Subset(@Subset(m;
 1 + @TextToNumber(@Middle(d3; 1; 1))); -1) + @Subset(@Subset(n; 
 @If(v3 > 19; @TextToNumber(@Right(d3; 1)); v3) + 1); -1));

REM "Trillions";
d4 := @Left(d; 3);
h4 := @Subset(@Subset(n; @TextToNumber(@Left(d4; 1)) + 1); -1);
v4 := @TextToNumber(@Right(d4; 2));

t4 := @Trim(@If(h4 = ""; ""; h4 + " Hundred ") + @Subset(@Subset(m;
 1 + @TextToNumber(@Middle(d4; 1; 1))); -1) + @Subset(@Subset(n;
 @If(v4 > 19; @TextToNumber(@Right(d4; 1)); v4) + 1); -1));

REM "Put it together";
@If(origNumber = "";"";origNumber < 0;"Negative ";"") + @Trim(@If(t0 +
 t1 + t2 + t3 + t4 = ""; "Zero"; @If(t4 = ""; ""; t4 + " Trillion ") +
 @If(t3 = ""; ""; t3 + " Billion ") + @If(t2 = ""; ""; t2 + " Million") +
 @If(t1 = ""; ""; t1 + " Thousand ") + t0)) + " Dollars and " +
 @If(c = ""; "00"; c) + " Cents"

How do you open a document in edit mode if it exists?

The following code will open in edit mode the first doc in the "UPref" view if it exists or create a new document if it doesn't exist. Use GetDocumentByKey on the view if you need to select a specific document first.

Dim session As New Notessession
Dim ws As New NotesUIWorkspace
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument

Set db = session.CurrentDatabase
Set view = db.GetView("UPref")

On Error Resume Next
Set doc = view.GetFirstDocument
If doc Is Nothing Then
 Set uidoc = ws.ComposeDocument("","","UPref")
Else
 ws.OpenDatabase "","","UPref"
 ws.EditDocument
End If

How do I remove erased fields that keep appearing in the Add Fields window?

Run a macro to remove the erased field's data from all documents.

  FIELD oldField1 := @Unavailable; 
  Select @ALL

Then, compact your database.

If this doesn't work, you may have run into a known bug with Notes. The workaround is to create a new form and copy the form over using copy/paste of all the fields (don't copy the entire form from the form list); you also may have to create the same fields w/ the same name but of type Text and then delete them before the compact. It's a tedious workaround, so hopefully, Lotus will get it fixed soon.


How do you retrieve a column total for a category?

As it turns out, @DbColumn will return totals and subtotals on categories, and not the individual line items. Therefore, if you have the correct hidden view, you don't have to resort to that lengthy @Sum at all!!

Case in point:

Apples 16
Red 10
Green 6
Oranges 22
Juicy 11
Firm 10
Mandarin 1
Bananas
13
Big 13
51

If you want to retrieve that 22 from the hidden view, don't use @DbLookup (which will return 11;10;1), instead use 2 @DbColumns:

x:="Oranges"; Usually you use an @Prompt to get this value
a:=@DbColumn("";"";"(Fruit Count)";1); Returns "Apples":"Oranges":"Bananas"
b:=@DbColumn("";"";"(Fruit Count)";3); Returns 16:22:13:51
c:=@Member(x;a); Look for where Oranges appears in the list (2nd)
d:=@If(c=0;-1;c); @Subset crashes if it sees a 0, so this is to prevent that
e:=@Subset(@Subset(b;d);-1); Select the proper (2nd) item out of the number list (22)
@If(c=0;"No Match";e) Other half of @Subset workaround, returns 22, the proper answer.


How do you sort and categorize a view based on months in chronological order?

Insert a hidden column just to the left of your month column. Make this column contain a numeric @month type value that will sort correctly, then sort it. The hidden column should be sorted but not categorized, while the visible month column should be categorized.
If you have multiple years to cope with, use

  (@Year(TheDate)-1900)*12 + @Month(TheDate)

in the hidden column so that everything sorts nicely, or you can use an extra categorization on @Year to the left of the month.


How do you open a Win32 File Dialog in LotusScript?

This is an example of how to call the standard file open dialog in Windows 95 or NT:

' From Andre Guirard
Option Public
Option Declare

Dim Filter As String
Dim FileName As String
Dim FileTitle As String
Dim TruncName As String

Dim VaultWIPRoot As String
Dim VaultWIPUserPath As String

Type tagOPENFILENAME
  lStructSize As Long
  hwndOwner As Long
  hInstance As Long
  lpstrFilter As String
  lpstrCustomFilter As Long
  nMaxCustFilter As Long
  nFilterIndex As Long
  lpstrFile As String
  nMaxFile As Long
  lpstrFileTitle As String
  nMaxFileTitle As Long
  lpstrInitialDir As String
  lpstrTitle As String
  Flags As Long
  nFileOffset As Integer
  nFileExtension As Integer
  lpstrDefExt As String
  lCustData As Long
  lpfnHook As Long
  lpTemplateName As Long     
End Type

Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (OPENFILENAME As tagOPENFILENAME)  As Long

Dim OPENFILENAME As tagOPENFILENAME

Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_ENABLEHOOK = &H20
Public Const OFN_ENABLETEMPLATE = &H40
Public Const OFN_ENABLETEMPLATEHANDLE = &H80
Public Const OFN_EXPLORER = &H80000                         
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_LONGNAMES = &H200000                       
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_NODEREFERENCELINKS = &H100000
Public Const OFN_NOLONGNAMES = &H40000                      
Public Const OFN_NONETWORKBUTTON = &H20000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_READONLY = &H1
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_SHAREFALLTHROUGH = 2
Public Const OFN_SHARENOWARN = 1
Public Const OFN_SHAREWARN = 0
Public Const OFN_SHOWHELP = &H10

Function OpenCommDlg ()
  Dim Title As String    
  Dim DefExt As String
  Dim szCurDir As String 
  Dim APIResults%
     
  'Give the dialog a caption title.
  Title = "Add supporting document" & Chr$(0)
     
  'Allocate string space for returned strings
  FileName = Chr$(0) & Space$(255) & Chr$(0)
  FileTitle = Space$(255) & Chr$(0)
     
  'If the user does not specify an extension, append TXT.
  DefExt = "TXT" & Chr$(0)
     
  'Set up the default directory
  szCurDir = Curdir$ & Chr$(0)
     
  'Set up the data structure before you call the GetOpenFileName
     
  OPENFILENAME.lStructSize = Len(OPENFILENAME)
     
  'If the OpenFile Dialog box is not linked to any form use this line.
  'It will pass a null pointer.
     
  OPENFILENAME.hwndOwner = 0&
    
  OPENFILENAME.lpstrFilter =  Filter
  OPENFILENAME.nFilterIndex = 1
  OPENFILENAME.lpstrFile = FileName
  OPENFILENAME.nMaxFile = Len(FileName)
  OPENFILENAME.lpstrFileTitle = FileTitle
  OPENFILENAME.nMaxFileTitle = Len(FileTitle)
  OPENFILENAME.lpstrTitle = Title
  OPENFILENAME.Flags = OFN_FILEMUSTEXIST
  OPENFILENAME.lpstrDefExt = DefExt
  OPENFILENAME.hInstance = 0
  OPENFILENAME.lpstrCustomFilter = 0
  OPENFILENAME.nMaxCustFilter = 0
  OPENFILENAME.lpstrInitialDir = szCurDir
  OPENFILENAME.nFileOffset = 0
  OPENFILENAME.nFileExtension = 0
  OPENFILENAME.lCustData = 0
  OPENFILENAME.lpfnHook = 0
  OPENFILENAME.lpTemplateName = 0
   
  'This will pass the desired data structure to the Windows API,
  'which will in turn it uses to display the Open Dialog form.   
  APIResults% = GetOpenFileName(OPENFILENAME)
    
  If APIResults% <> 0 Then          
    FileName = Cstr( OPENFILENAME.lpstrFile )
    FileTitle = Cstr( OPENFILENAME.lpstrFileTitle )        
    OpenCommDlg = 1
  Else 
    OpenCommDlg = 0
  End If
End Function

Sub Initialize
  If (OpenCommDlg = 1) Then
    Print " "
  Else
    Print "No documents were attached."
  End If
End Sub


For non-Windows Notes 4.5 and above users, you can use:

@Prompt([LocalBrowse])


Can you dynamically change the color of the form?

You can put a number in the $papercolor field when the form is first opened.
This is from the code in the Color Swatches database. You can set the field "ColorName" to the name you see in the InfoBox's Color Chooser and put this formula in the $papercolor field:

@Member(ColorName;

"black":
"white":
"red":
"green":
"blue":
"magenta":
"yellow":
"cyan":
"dark red":
"dark green":
"dark blue":
"dark magenta":
"dark yellow":
"dark cyan":
"gray":
"light gray":
"white":
"vanilla":
"parchment":
"ivory":
"pale green":
"sea mist":
"ice blue":
"powder blue":
"arctic blue":
"lilac mist":
"purple wash":
"violet frost":
"seashell":
"rose pearl":
"pale cherry":
"white":
"blush":
"sand":
"light yellow":
"honeydew":
"celery":
"pale aqua":
"pale blue":
"crystal blue":
"light cornflower":
"pale lavender":
"grape fizz":
"pale plum":
"pale pink":
"pale rose":
"rose quartz":
"5% gray":
"red sand":
"buff":
"lemon":
"pale lemon lime":
"mint green":
"pastel green":
"pastel blue":
"sapphire":
"cornflower":
"light lavender":
"pale purple":
"light orchid":
"pink orchid":
"apple blossom":
"pink coral":
"10% gray":
"light salmon":
"light peach":
"yellow":
"avocado":
"leaf green":
"light aqua":
"light turquoise":
"light cerulean":
"azure":
"lavender":
"light purple":
"dusty violet":
"pink":
"pastel pink":
"pastel red":
"15% gray":
"salmon":
"peach":
"mustard":
"lemon lime":
"neon green":
"aqua":
"turquoise":
"cerulean":
"wedgewood":
"heather":
"purple haze":
"orchid":
"flamingo":
"cherry pink":
"red coral":
"20% gray":
"dark salmon":
"dark peach":
"gold":
"yellow green":
"light green":
"caribbean":
"dark pastel blue":
"dark cerulean":
"manganese blue":
"lilac":
"purple":
"light red violet":
"light magenta":
"rose":
"carnation pink":
"25% gray":
"watermelon":
"tangerine":
"orange":
"chartreuse":
"green":
"teal":
"dark turquoise":
"light slate blue":
"medium blue":
"dark lilac":
"royal purple":
"fuchsia":
"confetti pink":
"pale burgundy":
"strawberry":
"30% gray":
"rouge":
"burnt orange":
"dark orange":
"light olive":
"kelly green":
"sea green":
"aztec blue":
"dusty blue":
"blueberry":
"violet":
"deep purple":
"red violet":
"hot pink":
"dark rose":
"poppy red":
"35% gray":
"crimson":
"red":
"light brown":
"olive":
"dark green":
"dark teal":
"spruce":
"slate blue":
"navy blue":
"blue violet":
"amethyst":
"dark red violet":
"magenta":
"light burgundy":
"cherry red":
"40% gray":
"dark crimson":
"dark red":
"hazelnut":
"dark olive":
"emerald":
"malachite":
"dark spruce":
"steel blue":
"blue":
"iris":
"grape":
"plum":
"dark magenta":
"burgundy":
"cranberry":
"50% gray":
"mahogany":
"brick":
"dark brown":
"deep olive":
"dark emerald":
"evergreen":
"baltic blue":
"blue denim":
"cobalt blue":
"dark iris":
"midnight":
"dark plum":
"plum red":
"dark burgundy":
"scarlet":
"60% gray":
"chestnut":
"terra cotta":
"umber":
"amazon":
"peacock green":
"pine":
"seal blue":
"dark slate blue":
"royal blue":
"lapis":
"dark grape":
"aubergine":
"dark plum red":
"raspberry":
"deep scarlet":
"70% gray":
"red gray":
"tan":
"khaki":
"putty":
"bamboo green":
"green gray":
"baltic gray":
"blue gray":
"rain cloud":
"lilac gray":
"light purple gray":
"light mauve":
"light plum gray":
"light burgundy gray":
"rose gray":
"80% gray":
"dark red gray":
"dark tan":
"safari":
"olive gray":
"jade":
"dark green gray":
"spruce gray":
"dark blue gray":
"atlantic gray":
"dark lilac gray":
"purple gray":
"mauve":
"plum gray":
"burgundy gray":
"dark rose gray":
"black") - 1


Can you open a Navigator using Lotuscript?

Use this to open the navigator named "NAV1":

  Call ws.OpenDatabase("",DbName,"NAV1","1")

where "1" opens the navigator in it's own window and a "0" causes it to open in the navigation pane.


How do you do @Explode in LotusScript?

There is no equivalent but here is a function that performs an @Explode:

Function AtExplode(strList As String, varSeparators As Variant) As Variant

'********************************************************************************************************************
' From ebrehault@amadeus.net
' Breaks a delimited string into its component elements and returns the elements in a string array
'
' Parameters:
' Input:
' strList: The delimited string to parse
' varSeparators: An array of strings representing the delimiters used in strList
'
' Return Value: An array of strings with each element representing an element in strList
'
'********************************************************************************************************************

Dim intI, intDone As Integer 'Loop control variables
Dim intPosTemp, intPosLastDelimiter, intPosNextDelimiter As Integer 'For determining position of last found and next delimiter in strList
Dim strLastDelimiter, strNextDelimiter As String 'The actual delimiters
last found and next occuring in strList
Dim strElement As String 'An element of strList
Dim astrElement() As String 'The array to return containing the elements of strList
Dim iastrElement As Integer 'Count of elements found in strList

'If an empty string is passed in, return an empty string
If Trim$(strList) = "" Then
  Explode = ""
  Goto Explode_Exit
End If

'Initialize the variables
iastrElement = 0
strLastDelimiter = ""
strNextDelimiter = ""
intPosLastDelimiter = 1 'The combination of intPosLastDelimiter and the Length of strLastDelimiter determine where the next element should start
intDone = False
intPosNextDelimiter = Len(strList) 'The default position for the next delimiter is the end of strList

'Loop through the potential delimiters to identify the next one. Store its position in strLIst and its text
For intI = Lbound(varSeparators) To Ubound(varSeparators)
  intPosTemp = Instr(1, strList, varSeparators(intI))
  If intPosTemp <> 0 And intPosTemp <= intPosNextDelimiter Then
    intPosNextDelimiter = intPosTemp
    strNextDelimiter = varSeparators(intI)
  End If
Next

'Process strList until intDone is true
Do
  'Get the next element in strList with extraneous spaces removed. The starting position of the next element is equal to the starting position
  'of the last delimiter found + the length of the last delimiter found (intPosLastDelimiter + Len(strLastDelimiter))
  If strNextDelimiter = "" Then
    'If strNextDelimiter is blank then we're getting the rest of the string.
    strElement = Trim(Mid(strList, intPosLastDelimiter + Len(strLastDelimiter)))
  Else
    'The length of the next element equals the position of the last character of the element (intPosNextDelimiter - 1) minus the position
    'one character before the first character of the element (intPosLastDelimiter + Len(strLastDelimiter) - 1)
    strElement = Trim(Mid(strList, intPosLastDelimiter + Len(strLastDelimiter),_
     intPosNextDelimiter - 1 - (intPosLastDelimiter + Len(strLastDelimiter) - 1)))
  End If
  If strElement <> "" Then
    'If the current element isn't blank, increment the count of elements and add it to the array of elements
    iastrElement = iastrElement + 1
    Redim Preserve astrElement(1 To iastrElement)
    astrElement(iastrElement) = strElement
  End If
  If strNextDelimiter <> "" And (intPosNextDelimiter + Len(strNextDelimiter) - 1) < Len(strList) Then
    'If you haven't reached the end of strList (strNextDelimiter <> "") and the last character of the last delimiter found
    'is not at the end of strList (intPosNextDelimiter + Len(strNextDelimiter) - 1 < Len(strList)

    'Set the Last delimiter variables equal to reflect the last delimiter found
    intPosLastDelimiter = intPosNextDelimiter
    strLastDelimiter = strNextDelimiter

    'Set the Next delimiter variables to assume there isn't one
    intPosNextDelimiter = Len(strList)
    strNextDelimiter = ""

    'Loop through the potential delimiters to identify the next one. Store its position in strLIst and its text
    For intI = Lbound(varSeparators) To Ubound(varSeparators)
      'Start looking with the character in strList after the end of the last delimiter found
      intPosTemp = Instr(intPosLastDelimiter + Len(strLastDelimiter), strList, varSeparators(intI))
      If intPosTemp <> 0 And intPosTemp <= intPosNextDelimiter Then
        'If the position of the current delimiter is less than the nearest one found so far, store it's position and text
        intPosNextDelimiter = intPosTemp
        strNextDelimiter = varSeparators(intI)
      End If
    Next
  Else
    'If you've reached the end of strList (strNextDelimiter = "") or the last character of the last delimiter found
    'is at the end of strList (intPosNextDelimiter + Len(strNextDelimiter) - 1 >= Len(strList) then you're done.
    intDone = True
  End If
Loop Until intDone

'Return the array containing the elements
Explode = astrElement

Explode_Exit:

End Function


Can you launch a URL without using InterNotes?

Put this formula in a button:

@Command([Execute]; "C:\\netscape\\netscape.exe"; "HTTP://www.xyzcorp.com")

Note that this will invoke netscape, so this form will not be cross-platform if you have other Notes clients.


How do you get the date for Easter of a given year?

REM "This formula returns the date of Easter day for the year of a given date D";
REM "Is valid until year 4000";
REM "Contributed from billingt@online.no";

D:=[30.07.97];
Year:=@Year(D);

c:=@Integer(Year/100);
n:=Year-19*@Integer(Year/19);
k:=@Integer((c-17)/25);
i:=c-@Integer(c/4)- @Integer((c-k)/3)+19*n+15;
ii:=i-30*@Integer(i/30);
iii:=ii-@Integer(ii/28)*(1-@Integer(ii/28)*@Integer(29/(ii+1))*@Integer((21-n)/11));

j:=Year+@Integer(Year/4)+iii+2-c+@Integer(c/4);
jj:=j-7*@Integer(j/7);
l:=iii-jj;
EasterMonth:=3+@Integer((l+40)/44);
EasterDay:=l+28-31*@Integer(EasterMonth/4);
@Date(Year;EasterMonth;EasterDay);

How do you hide the design of a database, but let the user see field names?

1) Hide the database design in the NSF.
2) Rename the hidden design database to an NTF template.
3) Put the NTF template in the Notes Data directory.
4) Create a new database from the NTF template.
5) Replace its design using NTF template.


Can you access Win32 registry keys in LotusScript?

This code goes in the declarations section

Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (Byval hKey As Long, Byval lpSubKey As String, phkResult As Long) As Long
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (Byval hKey As Long, Byval lpSubKey As String, Byval ulOptions As Long, Byval samDesired As Long, phkResult As Long) As Long
Declare Function RegCloseKey Lib "advapi32.dll" (Byval hKey As Long) As Long
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (Byval hKey As Long, Byval lpValueName As String, Byval lpReserved As Long, lpType As Long, Byval lpData As String, lpcbData As Integer) As Long
Declare Function RegEnumKey Lib "advapi32.dll" Alias "RegEnumKeyA" (Byval hKey As Long, Byval dwIndex As Long, Byval lpname As String, Byval cbName As Long) As Long
Declare Function RegEnumKeyEx Lib "advapi32.dll" Alias "RegEnumKeyExA" (Byval hKey As Long, Byval dwIndex As Long, Byval lpname As String, lpcbName As Long, Byval lpReserved As Long, Byval lpClass As String, lpcbClass As Long, lpftLastWriteTime As FILETIME) As Long

Declare Function RegSetValueEx& Lib "advapi32.dll" Alias "RegSetValueExA" _
(Byval hKey As Long, Byval lpValueName As String, Byval Reserved As Long, Byval _
dwType As Long, Byval lpData As String, Byval cbData As Long)

Declare Function RegCreateKey& Lib "advapi32.dll" Alias "RegCreateKeyA" (Byval _
hKey As Long, Byval lpSubKey As String, phkResult As Long)

Type FILETIME
     dwLowDateTime As Long
     dwHighDateTime As Long
End Type

'-- Constant Definitions for WIN32API
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS = &H80000003
Const HKEY_PERFORMANCE_DATA = &H80000004

Const SYNCHRONIZE = &H100000
Const STANDARD_RIGHTS_READ = &H20000
Const STANDARD_RIGHTS_WRITE = &H20000
Const STANDARD_RIGHTS_EXECUTE = &H20000
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const STANDARD_RIGHTS_ALL = &H1F0000
Const KEY_QUERY_VALUE = &H1
Const KEY_SET_VALUE = &H2
Const KEY_CREATE_SUB_KEY = &H4
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const KEY_CREATE_LINK = &H20
Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
Const KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
Const KEY_EXECUTE = (KEY_READ)
Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))
Const ERROR_SUCCESS = 0&

' Reg Data Types...
Const REG_NONE = 0                       ' No value type
Const REG_SZ = 1                         ' Unicode nul terminated string
Const REG_EXPAND_SZ = 2                  ' Unicode nul terminated string
Const REG_BINARY = 3                     ' Free form binary
Const REG_DWORD = 4                      ' 32-bit number
Const REG_DWORD_LITTLE_ENDIAN = 4        ' 32-bit number (same as REG_DWORD)
Const REG_DWORD_BIG_ENDIAN = 5           ' 32-bit number
Const REG_LINK = 6                       ' Symbolic Link (unicode)
Const REG_MULTI_SZ = 7                   ' Multiple Unicode strings


This sample code sets some registry keys associated with IBM's Global Network dialer:

KeyName$ = "Software\IBM Global Network\Dialer\Calling\From\"+ActiveLocation.LocName
res1& = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName$ , 0, KEY_ALL_ACCESS, keyhandle)
If res1& <>ERROR_SUCCESS Then
  res1& = RegCreateKey( HKEY_CURRENT_USER, Keyname$, KeyHandle )
End If
If res1& = ERROR_SUCCESS Then
  res = setDialerReg( keyHandle, ThisPhone )
End If
Call RegCloseKey(keyhandle)
          
KeyName$ = "Software\IBM Global Network\Dialer\Settings"
res2& = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName$ , 0, KEY_ALL_ACCESS, keyhandle)
res = setDialerReg( keyHandle, ThisPhone )
Call RegCloseKey(keyhandle)
          
If res1& <> ERROR_SUCCESS And res2& <> ERROR_SUCCESS Then
  Msgbox "The Advantis Dialer is not installed correctly - please contact support"
  Exit Sub
Else
  DialerProgram$ = "c:\Program Files\IBM Global Network\IDialer.EXE"
  KeyName$ = "Software\IBM Global Network\Dialer\Install"
  res3& = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName$ , 0, KEY_ALL_ACCESS, keyhandle)
  If res3& = ERROR_SUCCESS Then
    Dim Ret_Type As Long
    Dim lpFileName As String
    Dim lpReturnedString As String*127
    Dim retSize%
    retSize% = 126
    res4& = RegQueryValueEx( keyhandle, "Directory", 0, Ret_Type, lpReturnedString, retSize% )
    If res4& = ERROR_SUCCESS Then
      DialerProgram$ = Left$(lpReturnedString, retSize%-1) +"\IDialer.exe"
    End If
  End If
  Call RegCloseKey(keyhandle)
  Print "Launching the Advantis Dialer " & DialerProgram$
  rc& = Shell( DialerProgram$ , 2) ' run the dialer and bring the focus to the foreground
End If


How do you launch an embedded object using LotusScript?

First use the extract file method of EmbeddedObjects class to save the file to a temporary directory then use the LotusScript "Shell" command to run the program with the temporary file.


How do you debug into the QueryModeChange and QuerySave events in LotusScript?

Create an Initialize event script for your document and put x=1 in it.
The bebugger will stop there when the document is opened.
Scroll to the appropriate event or events and put a break point into them.
Go back to the initialize event and click the continue or step into button.


How do I refresh a document's fields after one field is changed?

Place this in the exiting event of the field that will trigger changes in other fields:

Sub Exiting(Source As Field)
  Dim workspace As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument
  Set uidoc = workspace.CurrentDocument
  Call uidoc.Refresh
End Sub

The "Refresh fields on keyword change" option does not work on anything other than static keyword lists.
One bad side-effect is that the uidoc.Refresh will cause all the field input validation formulas to be run; you may want to cause the refresh to happen only if all the fields with input validation have been filled in.


How do you change the title of a dialog box?

With the @DialogBox macro, the dialog box Window Title defaults to "Lotus Notes". Placing a form title in the Window Title property of the form has no effect. However, there is this undocumented version of @DialogBox:

@DialogBox(<Form>; [AutoHorizFit] : [AutoVertFit]; "Title Here")

Here are several other undocumented options:

[NoCancel] No Cancel button
[NoFieldUpdate] Does not return anything to calling form/document
[ReadOnly] Makes the dialogbox readonly


How do you remove an element from a Textlist field?

You can use the LotusScript Evaluate function to run the Notes V3 version of this FAQ. If you prefer a pure LotusScript version, this example takes a text list (tl1) with the values "Elem1":"Elem2":"Elem3" and turns it into "Elem1":"Elem3". You will have to do some fiddling with the Redim Statement to make sure that you have enough space (eg, the element you wish to remove is not in the list).

Dim db As NotesDatabase
Dim ws As New NotesUIWorkspace
Dim session As New NotesSession
Dim i As Integer
Dim j As Integer
Dim textList As Variant
Dim outList As Variant

Set uidoc = ws.CurrentDocument        ' get the current uidoc
Set doc = uidoc.Document              ' get the backend doc

textList = doc.GetItemValue("tl1")    ' Get the list and put it in a variant
Redim outList(Ubound(textList)-1) As Variant    ' Dim the outlist
j = 0
For i = 0 To Ubound(textlist)         ' Loop through and check for the element to be removed
  If textList(i) <> "elem2" Then      ' Check for the value to replace (could be a variable)
    outList(j) = textList(i)          ' Populate the outlist
    j = j + 1
  End If
Next
Call doc.ReplaceItemValue("tl1",outList)        ' replace the original
list with the outlist
Call uidoc.Reload                     ' reload the UIDoc with the new backend values


How do you avoid error messages with DBLookup?

TempVar := @DbLookup();
@If(@IsError(TempVar); 'perform desired error response'; 'perform desired
action on TempVar')

TempVar is used to hold the results and will also hold the special "error" value for comparison.


How do you find the elements which are unique to a list?

This will get the elements which are unique to List B:

UniqueToB:= @Trim( @Replace( ListB, ListA, ""))


Why don't my changes to a Rich Text field show up immediately?

Unlike text or time fields, you need to close and reopen the uidoc to see changes that are made on rich text fields. You have to do something like:

  Dim ws As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument

  Set uidoc = ws.CurrentDocument

  Dim doc As NotesDocument
  Set doc = uidoc.Document
  ' make changes to back-end document's Rich Text fields here
  Call uidoc.Close
  Set uidoc = ws.EditDocument(True, doc)

Here is this code applied to place a graphical logo from a central database onto a form:

Sub Postopen(Source As Notesuidocument)
'From Rich_Collette@siemon.com
'This routine copies a logo from a ListMaintenance form to this newly created LetterHead.
  Dim ListDoc As NotesDocument
  Dim doc As notesDocument
  Dim db As NotesDatabase
  Dim ListItem As notesRichTextItem
  Dim docItem As NotesRichTextItem
  Dim view As notesview
  Dim workspace As New NotesUIWorkspace
  'get the doc behind the new UIDoc
  Set doc=source.document
  'get the handle to the item that holds the Logo
  Set docItem=doc.GetFirstItem("LogoRTF")
  'check if Logo is already there from previous call to this routine
  If (docItem.ValueLength > 10) Then ' For some reason the value is > 0 even if the item is empty.
    Exit Sub
  End If
  'get handle to this database
  Set db=doc.ParentDatabase
  'form name isn't set on newly created docs, must set the value
  doc.form="LetterWithLogo"
  'get the "List" document that contains a logo in the RTFItems field
  Set view = db.GetView( "List Maintainence" )
  Set ListDoc = view.GetDocumentByKey( "LetterLogo", True )
  'if you don't remove the item prior to seting its value, you get an error message about the types not being equivalent
  Call doc.RemoveItem ("LogoRTF")
  Set ListItem = ListDoc.GetFirstItem("RTFItems")
  Set docItem = doc.CopyItem( ListItem, "LogoRTF" )
  'close the uidocument that is currently open on the user's screen
  Call source.close
  'reopen the document
  Set source = workspace.EditDocument( True, doc )
End Sub

When composing a UIDocument, RTF fields are stored on the backend NotesDocument as NotesItems rather than as NotesRichText items.ÿÿ They are not converted to a true RichTextItem on the backend Notesdocument until the Notesdocument is saved.ÿÿ Therefore, if you try to do:
Set rtfItem2 = doc.CopyItem( RTFItem1, "LogoRTF" )
after getting rtfItem1 from an existing RTF field prior to saving the notesdocument it is on, you are actually trying to copy an RTF field into a regular NotesItem and it gives you a data type error.


Rich sent in another example that creates and displays a rich text field without requiring that the back-end doc get saved first:


Sub Initialize
  'How to populate a new rich text field via backend classes and display without having to save the backend document
  '
  'If this is an existing saved document, then most of this is not needed, you just append to the existing RTF, close the UIDOC and edit the document
  'similar to what is done at the very end of this code
  '
  'Created by Richard Collette, CLP Principal Developer
  'rcollette@yahoo.com
  '
  'This demo needs a single form called "DemoDoc" - on the form place a field called "myRTF"
  '
  'Please note an actual application would test for "is Nothing" prior to using objects to insure they were instantiated.
  'This was eliminated here to provide a more concise example
  '
  'Caveat:   When closing and reopening a uidoc via its backend NotesDocument, the uidoc loses all notion that it is a response document and will save
  'as a regular document.  If you need a response document, you must capture the parent documentUNID (the selected document) and make the new
  'document a response using the MakeResponse method.
  Dim session As New NotesSession
  Dim doc As NotesDocument
  Dim tmpRTItem As NotesRichTextItem
  Dim RTItem As NotesRichTextItem
  Dim uiws As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument
  Dim styleHeadline As NotesRichTextStyle
  Dim styleNormal  As NotesRichTextStyle
  Dim item As NotesItem

  'compose the new document, or you can grab the current document that is on the workspace
  Set uidoc=uiws.composeDocument("", "" , "DemoDoc")
  If uidoc Is Nothing Then Exit Sub
  Set uidoc=uiws.currentDocument
  'get the backend document
  Set doc=uidoc.document
  'Create a temporary Rich Text Field that won't be saved
  Set tmpRTItem= New NotesRichTextItem( doc , "RTFTemp")
  tmpRTItem.saveToDisk=False
  'create the style objects for setting text properties
  Set styleHeadline=session.createRichTextStyle()
  Set styleHeadline=session.createRichTextStyle()
  Set styleNormal=session.createRichTextStyle()
  styleHeadline.bold=True
  styleHeadline.fontsize=14
  styleNormal.bold=False
  styleNormal.fontsize=10
  'Add text, images, etc to the temporary rich text field
  Call tmpRTItem.appendStyle(styleHeadline)
  Call tmpRTItem.AppendText( "Headline" )
  Call tmpRTItem.appendStyle(styleNormal)
  Call tmpRTItem.AddNewLine(1)
  Call tmpRTItem.AppendText( "Normal Text")
  '**********************************The meat and potatoes of this demo starts here**********************************************************
  'form name isn't stored on the composed NotesDocument until it is saved.  Set the form name so we can re-edit the document and it will know what form to use.
  doc.form="DemoDoc"
  'don't prompt the user to save the document, set this back to "1" at the end of the code if you want the user to be able to save the document
  doc.saveOptions="0"
  'this causes two RTItems of the same name (RTFTemp) to be created on the back end document, they get combined into one only when the NotesDocument is saved, this makes RTF's difficult to work with
  Call uidoc.close
  'remove the RTF field to be displayed becuase it really isn't an RTF until the document is saved, another reason why RTFs are so difficult to work with
  If (doc.isNewNote) Then
    Call doc.removeItem("myRTF")
  End If
  'get the first of the two RTItems that were created during the close event, the second one is empty
  Set tmpRTItem=doc.getFirstItem("RTFTemp")
  'because the temporary RTF item was formated during UIDOC close process, we can now copy it to our actual document field.
  'this code will not work without using a temporary RTFItem
  Set RTItem = doc.CopyItem( tmpRTItem, "myRTF" )
  'remove the temporary RTF Item from the backend document
  Call doc.removeItem("RTFTemp")
  'open the document in read mode and don't allow change to edit mode   (any other mode possible)
  Set uidoc=uiws.editDocument(True,doc)
  Set doc=uidoc.document
  'allow the user to save the document
  doc.saveOptions="1"
  'prevent SaveOptions from saving on the document
  Set item=doc.getFirstItem("saveOptions")
  item.saveToDisk=False
End Sub

How do signatures and sections in a form work?
A section will be signed if a field within it is edited, and that field is marked for signing when saved within a section. Sections aren't really signed at all - the field is - but the client notices the field's inside a section and makes it look like the section was signed. Different sections can be signed by different people.

When saving, Notes will sign all sections to which the user has access - even if signed before by that user or someone else. So, if you want a section signed and that signature to last, you must change the section's access control list to deny permssion to anyone else that might edit the document. Even then, if the signatory edits some other part of the document, the section will get re-signed. To avoid this, it's probably possible to make the section editable by no-one.

Note that the section ACL appears to be just a textlist field in the actual document (i.e. all the section handling is part of the form handling), so permissions can be re-widened (and re-signature etc. re-enabled) from a macro.

What does the @Db NoCache parameter do?
NoCache means that every time the @Db Function is executed, it will look at the current state of the Lookup View. If you do not use NoCache, the @Db Function will default to Caching the Lookup View the first time it executes. For Lookup Views which do not change rapidly (minute by minute), you should allow Notes to Cache the Lookup View. The difference in performance is tremendous.

How do you generate unique document numbers?
Because of the nature of Notes database replication, there is no way to generate unique document numbers. What is normally done to give each document a unique key is to concatenate the users name or initials with the date, and the time of document creation. An example can be found in Lotus Notes Call Tracking Database example. Another example is below:

TimeNow := @Now;
YearString := @Right(@Text(@Year(TimeNow)); 2);
MonthString := @Select(@Month(TimeNow); "01"; "02"; "03"; "04"; "05"; "06"; "07"; "08"; "09"; "10"; "11"; "12");
DayNumber := @Day(TimeNow);
DayString := @Select(DayNumber; "01"; "02"; "03"; "04"; "05"; "06"; "07"; "08"; "09";  @Text(DayNumber));
HourNumber := @Hour(TimeNow);
HourString := @If(HourNumber = 0; "00"; @Select(HourNumber; "01"; "02"; "03"; "04"; "05"; "06"; "07"; "08"; "09"; @Text(HourNumber)));
MinuteNumber := @Minute(TimeNow);
MinuteString := @If(MinuteNumber = 0; "00"; @Select(MinuteNumber; "01"; "02"; "03"; "04"; "05"; "06"; "07"; "08"; "09"; @Text(MinuteNumber)));
SecondNumber := @Second(TimeNow);
SecondString := @If(SecondNumber = 0; "00"; @Select(SecondNumber; "01"; "02"; "03"; "04"; "05"; "06"; "07"; "08"; "09"; @Text(SecondNumber)));
UniqueID := YearString + MonthString + DayString + HourString + MinuteString + SecondString + @Left(@Name([CN];@UserName); 1) + @MiddleBack(@Name([CN];@UserName); " "; 1)

Note that if this code is called twice, it doesn't take into account that there may be duplicate values. To prevent this case, you have to have a hidden view with all the unique numbers sorted. Then, do a @DbLookup to see if the value is already used.

For Notes 4 and above, you can use the @Unique function to get Notes' unique document ID.


What happened to Tools\RefreshFields that was in Notes 3.x?

There is now no menu option for refreshing fields; you have to make a SmartIcon or Action that uses either:

@Command([ToolsRefreshAllDocs])

or
@Command([ToolsRefreshSelectedDocs])


How do you do a data import/merge using Lotuscript?

This function can be placed in an action button in a database:

Sub Initialize
 On Error Goto _Error

 Dim bFileOpen As Integer
 Dim session As New NotesSession
 Dim db As NotesDatabase
 Set db = session.CurrentDatabase

 Dim view As NotesView
 Dim doc As NotesDocument
 Set view = db.GetView( "(CleanAddress)" )
 Set doc = view.GetFirstDocument

  ' The Fields we are going to import
 Dim Field1 As String
 Dim Field2 As String

  ' The unique field for each record
 Dim UniqueID As String

  ' Name of file to get from user
 Dim FileName As String

 If Not (doc Is Nothing) Then
   FileName  = Inputbox$("Enter your import file name: ", "Data Import", "C:\")
   If (FileName = "") Then
     Messagebox ("Import has been cancelled")
     Exit Sub
   End If
 Else
    ' There is nothing to merge into
   Messagebox ("Nothing to merge into! Are you sure you have already imported this file?")
   Exit Sub
 End If

  ' Open the file
 Dim fileNum As Integer
 fileNum = Freefile()
 Open FileName For Input As fileNum
 bFileOpen = 1

 Dim item As NotesItem
  ' Until we eof
 Do Until Eof (fileNum)
   Input #fileNum, UniqueID, Field1, Field2
   If (UniqueID > "") Then
     Set doc = view.GetDocumentByKey(URN)
     If Not (doc Is Nothing) Then
       doc.Field1 = Field1
       doc.Field2 = Field2
       Call doc.Save(True, False)
     Else
       Messagebox("File contains a record that is not in the database " + UniqueID)
     End If
   Else
     Messagebox("File contains an record without a unique id")
   End If
 Loop

  ' Close file
 Close fileNum
 bFileOpen = 0

 Messagebox("File imported successfully")
 Exit Sub

_Error:
 If (bFileOpen = 1) Then
   Close fileNum
 End If
 Messagebox("Error importing data: " + Error$)
End Sub


How do you lock a document that is being edited?

Eric Koeler has written a set of functions for doing this in Notes 4.x. You can grab the code and a code sample at his web site. The Lotuscript code works by adding a lock field to the document the user wishes to edit and then immediately saving the document; when other users try to open the document, they will see that there is a lock field so they cannot edit the document.
This technique will only work if the database is on a single server (no replication). There is also a small chance for a race condition if two users manage to read a document simultaneously without the lock. Finally, if the user's system crashes while editing this locked document, the document will remain locked unless you implement some sort of emergency unlock mechanism.


How can I see if the directory exists using LotusScript?

You can use the DIR$ command like so:

If Dir$(dirName, ATTR_DIRECTORY) = "" Then
     'Directory does not exist
Else
     'Directory does exist
End If


How can you tell if a view is Private?

There is no property in the view thtat lets you do this, but you can look at the design note for the view via this function:

Function IsPrivateView(v As Variant) As Integer

     ' From Hugh Pyle@NIP
     ' Since LotusScript doesn't give us a view property for this, we have to do the work ourselves.
     ' This is determined by opening the view note and checking for $Flags item containing the character "V".
     '
     Dim vdoc As NotesDocument
     Dim db As NotesDatabase
     '
     IsPrivateView=False
     If Not (v Is Nothing) Then
          Set db=v.Parent
          Set vdoc = db.GetDocumentByUnid( v.UniversalID )
          If Not (vdoc Is Nothing) Then
               If vdoc.HasItem("$Flags") Then
                    If Instr(vdoc.GetItemValue("$Flags")(0), "V") Then
                         IsPrivateView=privateview%
                    Elseif Instr(vdoc.GetItemValue("$Flags")(0), "p") Then
                         IsPrivateView=privateonfirstuse%
                    End If
               End If
          End If
     End If
End Function


How do you check if an RTF field is empty?

This interesting workaround comes from [email] Alan Keele. It does cause a little bit of UI flicker, but works on the front-end and back-end:

Function IsRTFNull(rtfield As String) As Integer
     
  'This function tests a Rich Text field to see whether or not it is null.  It returns TRUE if the field is null, and
  'returns FALSE if the field is not null.  It works even if the rich text field contains a file attachment, 
  'doclink, or OLE object but does not contain any text.
     
  On Error Goto Errhandle
     
  Dim workspace As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument
  Set uidoc = workspace.CurrentDocument
     
  'Store the name of the field that currently has focus.  Note:  if this function is being called from a form button,
  'currentfield will be null (because the button has the focus, and not a field).  If this function is called
  'from an action button, and if the cursor is in a field, then currentfield will correctly store the name 
  'of the field that has focus.
  currentfield = uidoc.CurrentField
     
  Call uidoc.GotoField(rtfield)
  Call uidoc.SelectAll
  'The next line will generate a 4407 error message if the Rich Text Field is null
  Call uidoc.DeselectAll
     
  'Return the cursor the the field that had focus before this function ran.  If the currentfield variable is null (because a button
  'or hotspot had focus, then the cursor will actually wind up getting left in the rich text field.
  If currentfield <> "" Then
    Call uidoc.GotoField(currentfield)
  End If
     
  IsRTFNull = False
     
  Exit Function
     
     
Errhandle:
  Select Case Err
  Case 4407
    'the DeselectAll line generated an error message, indicating that the rich text field does not contain anything
    If currentfield <> "" Then
      Call uidoc.GotoField(currentfield)
    End If
    IsRTFNull = True
  Exit Function
  Case Else
    'For any other error, force the same error to cause LotusScript to do the error handling
    Error Err
  End Select 
End Function


How do you log off a Notes user so you can force user revalidation?

You can use the following @Command:

  @Command([ToolsUserLogoff])


How do you calculate the week number in a year of a given date?

This formula satisfies ISO 8601:1988:

REM "This formula satisfies ISO 8601:1988";
REM "Formulae updated : 08.28.1997 ";
REM "by Stephen P.R. Renton (sprenton@mcmail.com)";
REM "Version: 1.01";
REM "Tested on : Lotus Notes Release 4.5";

REM "D is the date of interest.";
D := @TextToTime(@Prompt([OKCANCELEDIT]; "Enter Date"; "Please enter a
date to convert to a week number:"; ""));
REM "D := [31/12/95]";

FirstOfYear := @Date(@Year(D); 1; 1);
LastOfYear := @Date(@Year(D); 12; 31);
FirstDayNum := @Weekday(FirstOfYear);
LastDayNum := @Weekday(LastOfYear);

REM "ISO weeks start on Monday and ends on Sunday.";
ISOFirstDayNum := @If(FirstDayNum = 1; 7; FirstDayNum - 1);
ISOLastDayNum := @If(LastDayNum = 1; 7; LastDayNum - 1);

REM "The first and last ISO week is the first";
REM "and last ISO week to include Thursday";
IsFirstWeek := 7 - ISOFirstDayNum > 2;
IsLastWeek := 7 - ISOLastDayNum < 4;
REM "The date of the first day of the first ISO week";
ISOFirstDay := @If(IsFirstWeek;
            @Adjust(FirstOfYear; 0; 0; 1 - ISOFirstDayNum; 0; 0; 0);
            @Adjust(FirstOfYear; 0; 0; 8 - ISOFirstDayNum; 0; 0; 0));
REM "The date of the last day of the last ISO week";
ISOLastDay := @If(IsLastWeek;
            @Adjust(LastOfYear; 0; 0; 7 - ISOLastDayNum; 0; 0; 0);
            @Adjust(LastOfYear; 0; 0; -ISOLastDayNum; 0; 0; 0));

REM "Date outside ISOFirstDay and ISOlastDay";
REM "are from the previous or next year";
REM "Return the ISO week number and exit";

FirstWeekNextYear := @If(D > ISOLastDay; @Return(@Prompt([OK]; "FWNY";
@Text(@Year(D)+1) + "W01")); NULL);

REM "I suspect this is where Julian dates would be useful";
REM "A recursive call could be used in a real language";
LastWeekLastYear := (D - @Adjust(FirstOfYear; -1; 0; 0; 0; 0; 0))/60/60/24/7;
AdjustLastWeek := 1 - (LastWeekLastYear - @Integer(LastWeekLastYear));
@Set("LastWeekLastYear"; LastWeekLastYear + AdjustLastWeek);
@If(D < ISOFirstDay;
@Return(@Prompt([OK]; "LWLY"; @Text(@Year(D) - 1) + "W" +
@Text(LastWeekLastYear))); NULL);

REM "If you get this far, the date falls into an ISO week this year";
REM "Convert the difference in seconds to weeks";
NumWeeks := (D - ISOFirstDay)/60/60/24/7;

REM "Fractions indicate that the date falls";
REM "in the middle of the ISO week";
WeekAdjust := 1 - (NumWeeks - @Integer(NumWeeks));
ISOWeekNum := NumWeeks + WeekAdjust;

REM "Conform to ISO 8601 format";
Pad:=@If(ISOWeekNum<10;"0";"");
Result := @Text(@Year(D))+"W"+Pad+@Text(ISOWeekNum);

@Prompt([OK];"Week number"; Result)

Here is another version that gives you a week number in another ISO format:

REM "Formulae Calculate the Week Number(01-53) for any Date. ";
REM "The output follows the ISO 8601:1988 standard: ex 1997-W31-4 for 1997.07.31 ";
REM "Formulae writer : Nikolai Aasen (nsaa@pvv.org), UNI Storebrand, Norway";
REM "Formulae written : 1997.07.30";
REM "Formulae updated : 1997.08.04";
REM "Version  : 1.03";
REM "Tested on   :Lotus Notes 4.6PreRelease2";
REM "This formulae is available in the";
REM "Lotus Notes FAQ: http://www.keysolutions.com/NotesFAQ/";
REM "More Calendar information in http://www.pip.dknet.dk/~pip10160/calendar.html"; 
REM "ISO 8601:1988 summary at: http://quake.stanford.edu/~lyle/ISOdate/Date.html";
REM "--------------------------------------------------------------------------------------------------";             
REM "Replace D with the date of interest.";
D := [1997.31.07];

REM "**************************";
REM"Calculate some data for this Year";
REM "**************************";
FirstOfYear := @Date(@Year(D); 1; 1);
LastOfYear := @Date(@Year(D); 12; 31);
FirstDayNum := @Weekday(FirstOfYear);
REM "ISO weeks start on Monday and ends on Sunday.";
ISOFirstDayNum := @If(FirstDayNum = 1; 7; FirstDayNum - 1);

REM " Week 1 of any year is the week that contains the first Thursday in January.";
REM "=1 if 1. jan = man - thu. WeekNumber is then 1, else 0";
IsFirstWeek := 7- ISOFirstDayNum >2;

REM "The first Monday after 1. jan this Year";
FirstMonday := 9 - ISOFirstDayNum;

REM "Number of Days from 1. jan to D";
DaysToDateD:=(D-FirstOfYear)/60/60/24+1;

REM "Number of days in Year(either 365 or 366)";
DaysInYear:=(LastOfYear-FirstOfYear)/60/60/24;

REM "Number of Weeks in Year. Most years have 52 weeks, but years that start on a 
Thursday and leapyears that start on a Wednesday have 53 weeks.";
NumberOfWeeksThisYear:=@If( (ISOFirstDayNum=4 | (ISOFirstDayNum=3 & 
DaysInYear=366));53;52 );

REM "***************************";
REM"Calculate some data for last Year  ";
REM "***************************";
FirstOfLastYear := @Date(@Year(D)-1; 1; 1);
LastOfLastYear := @Date(@Year(D)-1; 12; 31);
FirstDayNumLast := @Weekday(FirstOfLastYear);
REM "ISO weeks start on Monday and ends on Sunday.";
ISOFirstDayNumLast := @If(FirstDayNumLast = 1; 7; FirstDayNumLast - 1);

REM "Number of days in Year(either 365 or 366)";
DaysInYearLast:=(LastOfLastYear-FirstOfLastYear)/60/60/24;

REM "Number of Weeks Last Year. Most years have 52 weeks, but years that start on a 
Thursday and leapyears that start on a Wednesday have 53 weeks.";
NumberOfWeeksLastYear:=@If( (ISOFirstDayNumLast=4 | (ISOFirstDayNumLast =3 & 
DaysInYearLast=366));53;52 );

REM "************************";
REM"Calculates the Week Number  ";
REM "************************";


DDayNum := @Weekday(D);
ISODDayNum := @If(DDayNum = 1; 7; DDayNum - 1);

REM"Is D in the last Week of the last Year?";
DayInLastWeek := @If((DaysToDateD<FirstMonday & IsFirstWeek = 0);
                                @Return( @Text(@Year(D)-1)+"-W"+@Text(NumberOfWeeksLastYear)+"-"+@Text(ISODDayNum));
                                 NULL);

REM "Calculate number of Complete Weeks Between D and 1.jan";
ComplNumWeeks:=@Integer((DaysToDateD-FirstMonday)/7);

REM "Are there remaining days?";
RemainingDays:=@If( (DaysToDateD+1-(FirstMonday+7*ComplNumWeeks))>0);

NumWeeks:= IsFirstWeek+ComplNumWeeks+1;

Out :=
@If(RemainingDays;
@If( (NumWeeks>52 & NumWeeks>NumberOfWeeksThisYear );
         @Return(@Text(@Year(D)+1)+"-W01-"+ @Text(ISODDayNum));
          @Return(@Text(@Year(D))+"-W"+@Right("0"+@Text(NumWeeks);2)+"-"+@Text(ISODDayNum))); 
@Return(@Text(@Year(D))+"-W"+@Right("0"+@Text(NumWeeks-1);2) +"-"+@Text(ISODDayNum)));
Out

This LotusScript version comes from Christian Meis:

'CalculateWeekNumbers: 

Option Declare


Sub Initialize
     
%REM
This short agent shows how the calendar week
function can be implemented.

Christian Meis, 09.04.1999
E-Mail: Christian.Meis@mlc.de
%END REM
     
  Dim dateval As Variant
  Dim test As String
     
  dateval = Cdat( Inputbox( "Please enter date: " ) )
  test = GetCalendarWeek( dateval )
     
  Messagebox( Cstr( dateval ) & " --> " & test )
     
End Sub


Function GetCalendarWeek( Byval inputdate As Variant ) As String
     
%REM
This function calculates the calendar week number 
(ISO standard) for a given date value. The format
function of LotusScript (parameter "ww") does not solve 
this problem. 


Monday is the first day of the week. Week #1 is the week 
that contains the 4th of January (ISO 8601). The week at the
end/beginning of the year belongs to the next/previous year,
if there are 3 days or less of that week in the year in question.

Christian Meis, 09.04.1999
%END REM
     
  Dim InputDateOffset As Integer
  Dim YearInQuestion As Integer
  Dim January4 As Variant
  Dim January4Offset As Integer
  Dim FirstMondayOfYear As Variant
  Dim January1Offset As Integer
  Dim December31Offset As Integer
  Dim weeknum As Integer
     
  ' The year value is preset with that of the input date
  YearInQuestion = Year( inputdate )
     
  ' Calculate offset to monday from the input date
  InputDateOffset = CalculateIsoWeekday( inputdate )
     
  ' Calculate offsets for the first/last day of the year
  January1Offset = CalculateIsoWeekday( Cdat( "01.01." & Cstr( YearInQuestion ) ) )
  December31Offset = CalculateIsoWeekday( Cdat( "31.12." & Cstr( YearInQuestion  ) ) ) 
     
  ' If the input date is before the 4th of January and the year starts with 
  ' a friday, saturday or sunday, the week belongs to the previous year
  If Month( inputdate ) = 1 And Day( inputdate ) < 4 And January1Offset > 3 Then
    YearInQuestion = YearInQuestion - 1
  End If
     
  ' If the input date is after the 28th of December and the year ends with 
  ' a monday, tuesday or wednesday, then the week belongs to the following year
  If Month( inputdate ) = 12 And Day( inputdate ) > 28 And December31Offset < 3 Then
    YearInQuestion = YearInQuestion + 1
  End If
     
  ' The 4th of January defines week #1
  January4 = Cdat( "04.01." & Cstr( YearInQuestion ) )
     
  ' Offset to the monday of week #1 
  FirstMondayOfYear = Cdat( January4 - CalculateIsoWeekday( January4 ) )
     
  ' The time range between the monday of week #1 and the monday
  ' of the week in question is divided by 7, plus 1 for the first week
  weeknum = ( inputdate - InputDateOffset - FirstMondayOfYear ) \ 7 + 1
     
  ' The return value is a string with the week number and the year
  GetCalendarWeek = Cstr( weeknum ) & " " & Cstr( YearInQuestion )
     
End Function


Function CalculateIsoWeekday( tmpdate As Variant ) As Integer
     
%REM
This function converts the weekday-numbers from the
standard function to an offset acc. to the ISO version
monday -> 0, ... , sunday -> 6
%END REM
     
  Dim n As Integer
     
  n = Weekday( tmpdate )
   
  If n = 1 Then ' sunday to end of week
    n = n + 7
  End If
     
  CalculateIsoWeekday = n - 2
     
End Function

How do you create response documents from a navigator hotspot?

Add this before your response document compose:

  @Command([OpenView]);

This will give focus back to the view so that the proper document is selected.


How do you provide context-sensitive help for your database?

There are two ways of supporting this in Notes:

1) Use text pop-ups. You can also use @DBLookup's in pop-ups to look up code in a "help" database; this allows you to let someone edit the help in a centralized place instead of on the documents or forms.

2) Use a button that opens a help document in a help view.

@Command([FileOpenDatabase]; @DbName; "helpview";Key;"1";"");
@Command([OpenDocument]; "0");
@Command([FileOpenDatabase]; @DbName; "helpview";"";"0";"");
@Command([FileCloseWindow]);


Can you get a filename from the user in Lotuscript?

This example illustrates how Lotuscript can be used to call a Win32 API Common File Dialog to get a file. Similiar techniques can be used on other operating systems:

Option Public
Option Declare


Dim Filter As String
Dim FileName As String
Dim FileTitle As String
Dim TruncName As String

Dim VaultWIPRoot As String
Dim VaultWIPUserPath As String

Type tagOPENFILENAME
     lStructSize As Long
     hwndOwner As Long
     hInstance As Long
     lpstrFilter As String
     lpstrCustomFilter As Long
     nMaxCustFilter As Long
     nFilterIndex As Long
     lpstrFile As String
     nMaxFile As Long
     lpstrFileTitle As String
     nMaxFileTitle As Long
     lpstrInitialDir As String
     lpstrTitle As String
     Flags As Long
     nFileOffset As Integer
     nFileExtension As Integer
     lpstrDefExt As String
     lCustData As Long
     lpfnHook As Long
     lpTemplateName As Long     
End Type

Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (OPENFILENAME As tagOPENFILENAME)  As Long

Dim OPENFILENAME As tagOPENFILENAME

Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_ENABLEHOOK = &H20
Public Const OFN_ENABLETEMPLATE = &H40
Public Const OFN_ENABLETEMPLATEHANDLE = &H80
Public Const OFN_EXPLORER = &H80000                         
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_LONGNAMES = &H200000                       
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_NODEREFERENCELINKS = &H100000
Public Const OFN_NOLONGNAMES = &H40000                      
Public Const OFN_NONETWORKBUTTON = &H20000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_READONLY = &H1
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_SHAREFALLTHROUGH = 2
Public Const OFN_SHARENOWARN = 1
Public Const OFN_SHAREWARN = 0
Public Const OFN_SHOWHELP = &H10

Function OpenCommDlg ()
     Dim Title As String    
     Dim DefExt As String
     Dim szCurDir As String 
     Dim APIResults%
     
     SetFileFilter
     
     'Give the dialog a caption title.
     Title = "Add supporting document" & Chr$(0)
     
     'Allocate string space for returned strings
     FileName = Chr$(0) & Space$(255) & Chr$(0)
     FileTitle = Space$(255) & Chr$(0)
     
     'If the user does not specify an extension, append TXT.
     DefExt = "BMP" & Chr$(0)
     
     'Set up the default directory
     szCurDir = Curdir$ & Chr$(0)
     
     'Set up the data structure before you call the GetOpenFileName
     
     OPENFILENAME.lStructSize = Len(OPENFILENAME)
     
     'If the OpenFile Dialog box is not linked to any form use this line.
     'It will pass a null pointer.
     
     OPENFILENAME.hwndOwner = 0&
     
     OPENFILENAME.lpstrFilter =  Filter
     OPENFILENAME.nFilterIndex = 1
     OPENFILENAME.lpstrFile = FileName
     OPENFILENAME.nMaxFile = Len(FileName)
     OPENFILENAME.lpstrFileTitle = FileTitle
     OPENFILENAME.nMaxFileTitle = Len(FileTitle)
     OPENFILENAME.lpstrTitle = Title
     OPENFILENAME.Flags = OFN_FILEMUSTEXIST
     OPENFILENAME.lpstrDefExt = DefExt
     OPENFILENAME.hInstance = 0
     OPENFILENAME.lpstrCustomFilter = 0
     OPENFILENAME.nMaxCustFilter = 0
     OPENFILENAME.lpstrInitialDir = szCurDir
     OPENFILENAME.nFileOffset = 0
     OPENFILENAME.nFileExtension = 0
     OPENFILENAME.lCustData = 0
     OPENFILENAME.lpfnHook = 0
     OPENFILENAME.lpTemplateName = 0
     
     'This will pass the desired data structure to the Windows API,
     'which will in turn it uses to display the Open Dialog form.   
     APIResults% = GetOpenFileName(OPENFILENAME)
     
     If APIResults% <> 0 Then          
          FileName = Cstr( OPENFILENAME.lpstrFile )
          FileTitle = Cstr( OPENFILENAME.lpstrFileTitle )        
          OpenCommDlg = 1
     Else 
          OpenCommDlg = 0
     End If
End Function

Sub Initialize
     If (OpenCommDlg = 1) Then
          Print " "
' use FileExt and other globals that contain the filename and extension, etc.
     Else
          Print "No documents were attached."
     End If
     
End Sub


Another way to do this is to use Notes' undocument API to do this. This is available on more platforms, but the usual caveats apply about using an undocumented API:

Declare Function NEMGetFile Lib "nnotesws" ( wUnk As Integer, Byval szFileName As String, Byval szFilter As String, Byval szTitle As String ) As Integer          'use nnotesws for Win95 and WinNT, inotesws for OS/2, and _nem for Win16

Sub Click(Source As Button)
  Dim szFileName As String*256
  Dim szTitle As String
  Dim szFilter As String
     
  szFilename = Chr(0)
  szTitle = "Select a database"
  szFilter = "Notes Databases|*.NSF|Notes Templates|*.NTF|Programs|*.EXE|All Files|*.*|"          'Use this format for ANY file type
  If NEMGetFile( 0, szFileName, szFilter, szTitle) <> 0 Then
    Messagebox szFileName
  End If
End Sub


How do you make a Computed For Display Rich Text Field?

Computed when composed formulas don't just execute when the document is composed. They execute when the form is edited and the field doesn't exist in the document. So they're really computed-when-field-doesn't exist formulas, which is also true for a new document.

Create another field whose formula deletes the rich text field on saving the document. For the rich text field, use a DbLookup to initialize the field. This gives you, in effect, a computed-for-display rich text field.


How do you look up all the people in a Group?

You can use this formula to get the Common Name list of persons in YourGroupName

  @Name([CN];@DbLookup("";@Subset(@MailDbName;1) : "Names.nsf";"Groups";"YourGroupName";
"Members"))


How do you make dynamically sized tables?

Starting with the second row, and for each subsequent row, select the entire row, and then in the Text Properties window, check the box "Hide paragraph if formula is true" with the formula:

( ! @IsDocBeingEdited & ThisRowKeyField = "" ) | LastRowKeyField = ""

Substitute the name of a required field in the current row for ThisRowKeyField, and the name of a required field in the previous row for LastRowKeyField. What this will do is suppress the display of any blank rows for read and print, and suppress all blank rows except one in edit mode.

Then you will need a way to "add" rows as they are entered by "un-hiding" them as needed, so put a button or hotspot in the form or on the action bar entitled "Add a row" with the formula:

@if(BottomRowKeyField="";
     @Command([RefreshHideFormulas]);
     @Prompt([OK];"Error";"Thirty rows is maximum"))


How do you send mail based on whether a field is modified?

Use a hidden computed field to monitor the target field for changes. For example, if the field you want to monitor is named "Dept", make a hidden computed field of the same type named "Monitor" with a formula similar to:

@If((Monitor=Dept)|(!@IsDocBeingSaved); @Return(Monitor); @Success);
@MailSend(Dept; ""; ""; ""; "Dept changed to yours"; "Doclink:"; [IncludeDoclink]);
Dept


How do you execute DOS commands from a formula?
Use the macro (note the use of the /C in the DOS command):

@Command([Execute]; "C:\\COMMAND.COM"; "/C DEL C:\\TEST.TXT")

How do I calculate the number of weekdays between two date fields?
The following formula counts the number of weekdays (but not weekend days):

diffDays := (EndDate - StartDate) / 86400 + 1;
strtDay := @Modulo(@Weekday(StartDate); 7);
endDay := @Modulo(@Weekday(EndDate); 7);
result := (diffDays - endDay + strtDay - 8) * 5 / 7 - @Max(-2; -strtDay) - @Min(1; endDay) + 5 - strtDay + endDay

Can I look up Multiple Keywords using @Db functions?
Yes, by separating the multiple keywords by a colon. Also, you can reference a field which contains multiple keywords, as long as that field has "Allow Multi-Values" checked ON.

How do you prevent LotusScript errors when handling deletion stubs in document collections?

Sometimes when you get a document collection for a LotusScript agent to handle, Notes passes you a deletion stub (this is probably a bug). In case you have to handle it, you can use this code:

' From Mike Woolsey
' IsErr_NOTES_ERROR is 4000
On Error lsErr_NOTES_ERROR Goto HandleDocError
dim failureCode as Integer    ' may be global
dim test as Variant
.....
set doc = dc.GetFirstDocument    ' say this is a FTS result collection, the doc may have been deleted since it was indexed
while not(doc is Nothing)
  failureCode% = 0
  test = doc.Items
  if failureCode% = 0 then   ' no error
    ....   ' handle document
  end if
  set doc = dc.GetNextDocument(doc)
wend
.....

HandleDocError:
  failureCode% = Err
  Resume next


How do you monitor your own threads in a discussion database?

Create a private folder. Add the discussion topics of interest to this folder. When responses are made to the topics, they will also show up in your private folder.


How do you notify users when documents are modified or added to a database?

Set up an agent for the database that will:
1) Run "If documents have been created or modified"
2) Act on "Newly modified documents"
3) Simple Action:"Send Newsletter Summary"

The result of this will be that anyone that you have entered in the To field will receive an e-mail message that includes a doc-link to the new or modified document. No scheduling is required.


How do you force the user to click an Edit action button to edit a document?

These scripts collectively force the user to use an action to place an existing document in edit mode. The action script places the current document in edit mode. The Postopen and Querychangemo de event scripts prevent the user from changing to edit mode through other means such as Actions - Edit Document (Ctrl+E).


'(Globals) object, (Declarations) event
Dim allowEdit As Integer

'(Form) object, Postopen event
Sub Postopen(Source As Notesuidocument)
  ' From Carl_Burgess@inter-tel.com
  'Let document pass if new or not in EditMode
  'Otherwise if existing document is in EditMode
  ' Set allowEdit so Querymodechange doesn't reprocess
  ' Turn EditMode off so document opens in read mode
  ' Tell the user to use the action
  If source.EditMode And Not source.IsNewDoc Then
    allowEdit = True
    source.EditMode = False
    Messagebox "Use Edit Mode action to edit document"
  Else
    allowEdit = False
  End If
End Sub

'(Form) object, Querymodechange event
Sub Querymodechange(Source As Notesuidocument, Continue As Variant)
  'Allow user to proceed, and turn off allowEdit if
  ' user clicked the action (allowEdit on)
  ' already processed by Postopen (allowEdit on)
  ' trying to get out of edit mode
  '  (allowEdit off but EditMode on)
  'Tell user to click action if changing existing document
  ' to edit mode and not already processed by Postopen
  '  (allowEdit and EditMode off)
  If allowEdit Or (source.EditMode And Not allowEdit) Then
    allowEdit = False
  Else
    Messagebox "Use Edit Mode action to edit document"
    continue = False
  End If
End Sub

'(Action) object, Click event
Sub Click(Source As Button)
  Dim workspace As New NotesUIWorkspace
  Dim uidoc As NotesUIDocument
  Set uidoc = workspace.CurrentDocument
  'Turn on allowEdit so Querymodechange will let it pass
  'Turn on EditMode
  allowEdit = True
  uidoc.EditMode = True
End Sub


How do you copy all parts of a script from one form to another?

1) Open the form in design mode.
2) Choose File/Export and select a file name.
3) Choose Current Object.
4) Go to the other form or the Script Library.
5) Choose File/Import.


Can I lookup Rich Text using @Db functions?
Yes, but if the value you are trying to look up is in a view column, it will fail.

How do you change fields based on the state of a separate keyword field?

There is an item in the field Properties box tab to the right of the "Basics" tab (the tab only appears for Keyword types and has a picture of a field). It's a little checkbox called "Refresh fields on keyword change".

In your "key" field, turn that little property on and your other fields will be recomputed upon an entry being made in the key field, just as if F9 had been pressed. The "key" field must be placed "before" (to the left and above) the fields to update within the form.

How do you keep doc.send() from crashing a background agent?

You can add these error handlers before you do the doc.send():

On Error Goto HandleError
On Error 4294 Resume Next
On Error 4295 Resume Next
On Error 4000 Resume Next
On Error 4160 Resume Next


How do you notify the author of a document when a response has been composed?

1) In the Main Document, Response and Response to Response forms, create a field called 'From', defaulting to

@Name([CN];@Username);

2) In the Response Form, create a hidden field called 'ParentFrom', defaulting (with inheriting on) to:
From

3) In the Reponse to Response, create a field called 'ParentFrom' defaulting to (with inheriting on):
ParentFrom:From

4) In Response and Response to Response forms, add another hidden computed for display field called 'Announce' with this formula:
@If(@IsDocBeingSaved;@Success;@Return(0));
List := @Trim(@Replace(ParentFrom;From;""));
@If(@Elements(List) > 0; @Success;@Return(0));
SendList := @Prompt([OKCANCELLIST]; "Mail Notify?"; "Send mail notification about your reply to ";"";List);
@If(@Elements(SendList) > 0; @Success;@Return(0));
@MailSend(SendList; ""; ""; "Ref:" + OriginalSubject; ""; "My reply: "; [IncludeDoclink])

[<a name="NT00001052">How do I make the "loser" of a replication/save conflict be the
"winner"?
</a>]

When you select the "loser" document and run this agent, it will be promoted to be a replication "winner". You can then delete the original "winner" document. Put this code into an agent that runs on selected documents:

Sub Initialize
  ' From Kevin Pauli (kcpauli@usa.net)
  Dim session As New NotesSession
  Set db = session.CurrentDatabase
  Set collection = db.UnprocessedDocuments
  Set doc = collection.GetFirstDocument
  Call doc.RemoveItem( "$Conflict" )
  If doc.IsResponse Then
    Set parent = db.GetDocumentByUNID( doc.ParentDocumentUNID )
    If parent.IsResponse Then
      Dim grandParent As NotesDocument
      Set grandParent = db.GetDocumentByUNID(parent.ParentDocumentUNID )
      Call doc.MakeResponse( grandParent )
    Else
      Call doc.RemoveItem( "$REF" )
    End If
  End If
  Call doc.Save( True, True )
End Sub


How can I control whether the @Db Function returns a list?
If the @DbLookup key is valid for multiple documents, it will return a list. All @DbColumns will return a list (unless there is only one value in the Lookup View). If you want to return only one value, use

@Subset(@DB Function; 1)
or
@Subset(@DB Function; -1)
.
If you want the @Db Function to return a list to a field, make sure that "Allow Multi-Values" is checked ON.

What causes the LotusScript error "Notes Error: Special Database object cannot be located."?


The database must have a default form and a default view. This is a known bug which should be fixed soon.


How do you return custom data types in LotusScript?

From Greg_Prickril@lotus.com:


Declarations
Class ReturnObj
  Private m_stName As String
  Private m_stType As String
     
  Property Get NameVal As String
    NameVal = m_stName$
  End Property
     
  Property Get TypeVal As String
    TypeVal = m_stType$
  End Property
     
  Sub new( arg_stName$, arg_stType$ )
    m_stName = arg_stName$
    m_stType = arg_stType
  End Sub   
End Class

Function Test() As ReturnObj
  Set Test = New ReturnObj( "Name", "Type" )
End Function

Initialize
  Dim var
  Set var = Test()
  Msgbox( var.NameVal )


Can you create Shared Actions?

You can create a blank subform that has actions, then use that subform in other forms.


Can you use regular expressions for string matching?

Look for the following formula to return true in each case.

To check if a character is alphanumeric...

@Matches(Char; "{A-z}")

To check for "a" or "b" or "c" ...

@Matches(Char; "{a-c}")

To check for all upper case alphanumeric plus the letters "a" or "b" or "c" and "d" ...

@Matches(Char; "{A-Za-d}")

To check for $321,000 or $321.000 but not $321.00 or $321,000- ...

@Matches(Dollar; "{$}{0-9}{0-9}{0-9}{,.}{0-9}{0-9}{0-9}")

To check for US long distance phone number...

@If(
  @Matches(PhoneNum; "{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}");
  @Success;
  @Failure("The Phone number must be in the format \"xxx-xxx-xxxx\"")
)

To check for social security ...
@Matches(SSNum;"{0-9}{0-9}{0-9}-{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}")


Can you run an Agent from LotusScript?

Using LotusScript under Windows, you can use OLE Automation of Notes to run an agent:

  Set s = CreateObject("Notes.NotesSession")
  Set db = s.GETDATABASE("", "db.nsf")
  Set a = db.GETAGENT("SomeAgent")
  Call s.SETENVIRONMENTVAR("AgentDocID", "ABCD")
  Call a.RUN

Parameters are passed to the agent using environment variables.

You can also run the agent directly:

  ' from Gary_VanCott@nvhin.com
  Dim db As New NotesDatabase("", "")
  Dim Agent As NotesAgent
  If (db.open("ServerName/Domain", "path\filename.nsf")) Then
    Set Agent = db.GetAgent("Agent Name")
    If Not(Agent Is Nothing) Then
      Call Agent.Run
    Else
      Msgbox "Agent not found..."
    End If
  Call db.close
  End If

How do you create Names, Readers, Authors fields in LotusScript?

You can use the "specialType" field of the NotesItem type:

  Dim variableName As New NotesItem( notesDocument, name$, value [,specialType%])

For example,
Dim TAuthor As New NotesItem(doc, "Author",  Auths, AUTHORS)
 TAuthor.IsSummary = True

will create a TAuthor field which is an author names field.


Can you implement exclusive locking across replicated databases?

This is impossible using Notes. Think about what would be required. You have a database replicated to multiple servers and clients. If a user opens a document, how would all the other unconnected databases know about this?
The only way to do this using Notes is to have a single un-replicated database. Normally, a redesign of the application is enough to work around this requirement.
Note that similiar problems occur if you try this with relational databases.


How do you add an Internet-style signature at the bottom of your mail messages?

Create a SmartIcon with this formula

  @Command([EditBottom]);
  @Command([FileImport];"ASCII Text"; "C:\\Notes\\data\\sig.txt")

and place your Internet-style signature in the sig.txt file.

You can then use this SmartIcon whenever you are in the body field of your Notes mail. It will append your signature to the message.
Here is another way to do this (from jessica@newmill.com) so that it happens on all memos you send out (but it requires your users to change each of your mail templates and also affects Notes mail messages because it affects all memos):

Open the New Memo form in design mode.
Click on the Body field to select it, then write the following in the "default value" section:
@NewLine+@NewLine+"Jessica Spinosa"+@NewLine+"New Millennium Inc."+@NewLine+"jessica@newmill.com"


How do you do @MailSend in Lotuscript?

Use the function below as follows:

  flag% = SendMailMemo("SendTo", "cc", "bcc", "Subject", "Body Text", NotesDocument)

If you pass a valid NotesDocument in as the last parameter, the mail memo is sent with a doclink to it. If you don't want to send a doclink, just pass the Nothing constant as the last parameter.

If the function encountered problems, it returns False, otherwise it returns True.

Function SendMailMemo(sendTo As String, _
                      cc As String, _
                      bcc As String, _
                      subject As String, _
                      body As String, _
                      linkTo As NotesDocument) As Integer
  On Error Goto ErrorHandler

  Dim mailDb As New NotesDatabase("", "")
  Dim mailDoc As NotesDocument
  Dim rtItem As NotesRichTextItem

  Call mailDb.OpenMail
  If (mailDb.IsOpen = False) Then Call mailDb.Open("", "")
  Set mailDoc = mailDb.CreateDocument
  mailDoc.Form = "Memo"
  mailDoc.SendTo = sendTo
  mailDoc.CC = cc
  mailDoc.BCC = bcc
  mailDoc.Subject = subject
  Set rtItem = mailDoc.CreateRichTextItem("Body")
  Call rtItem.AppendText(body)
  If Not(linkTo Is Nothing) Then
    Call rtItem.AddNewLine(2)
    Call rtItem.AppendDocLink(linkTo, "Double-click to open document")
  End If
  Call mailDoc.Send(False)
  SendMailMemo = True
  Exit Function

 ErrorHandler:
  Print "Error " & Str$(Err) & ": " & Error$
  Resume TheEnd

 TheEnd:
  SendMailMemo = False
End Function


Can you dynamically hide/unhide sections of a form?

Put a keyword field on the form and use the 'refresh fields on keyword change' property of the keyword field. If the user changes the keyword field, the hide when formulas are re-evaluated and the form is redisplayed.

How do you update a field in response documents after it is changed in the parent document?

Assumptions:
1) The name (or synonym) of the Response form is "TASK" and it inherits field values.
2) The name of the field to synchronize is "STATUS" in both Project and Task forms. This is computed when composed to inherit from the parent form.

Include the following Script code in the QuerySave event of the parent form:

Sub QuerySave(Source As Notesuidocument, Continue As Variant)
  Dim Collection As NotesDocumentCollection
  Dim Doc As NotesDocument
  Dim Form, ParentStatus, Status As String
     
  Set Doc = Source.Document
  Set Collection = Doc.Responses
  Set Doc = Collection.GetFirstDocument
  ParentStatus = Source.FieldGetText("STATUS")
  While Not ( Doc Is Nothing )
    Form = Doc.GetItemValue("Form")(0)
    Status = Doc.GetItemValue("Status")(0)
    If (Form = "TASK")And (Status <> ParentStatus) Then
      Call Doc.ReplaceItemValue( "STATUS", ParentStatus )
      Call Doc.Save (True, False)
    End If
    Set Doc = Collection.GetNextDocument(Doc)
  Wend
End Sub

Companies with Notes Applications

* GroupQuest Software
* Application Partners
* Groupware Technologies
* InfoImage (makers of Essential Tools, a set of server admin tools)
* Cambridge Software Group
* ALI Technologies
* Ives Development
* Candle/Cleversoft
* Mayflower Software
* Casahl Technology
* Brainstorm Technologies
* QDM
* Binary Tree (makers of BT Migration Suite and eTeam)
* Solutions By Design (makers of NavMaker, a Notes Navigator editor)
* Business Evolution (makers of InteractPro, a Java chat environment for Domino)
* AppJunction
* Technovations International (makers of Notes capacity planning tools)
* Extracomm Technologies (makers of ExtraFax)
* G2 Associates (makes of ProActive Assistant, a Notes stress-testing tool)
* Genii Software (makers of the Midas Rich Text LSX)
* Metaware bv
* Surety Technologies (makers of Digital Notary Accelerator for Lotus Domino)
* GSX Groupware Solutions (makers of the GSX Administration Suite)
* GlobalServe (makers of PageMe! pager gateway and Sales Accelerator: Contact
Management System)
* xorTech Systems (makers of InfoSync, a client replication admin tool)
*
ErgoTech (makers of Act! For Notes)
* Greyfriars Consulting Group, Inc. (makers of Domino business components)
* DPI Services (makers of QMX, quality management software)
* DataMirror (makes of a Notes/ODBC replication tool)
* GFI (makers of FAX gateway, Workflow and Internet gateway software)
* CommVault (makers of CommVault for Notes, a doc-level backup program)
* ProjectEdge (makers of a construction project management application)
* Jagre (makers of version control and change management software)


Sources of Notes API Information

* Rick Gansler's Mac API Presentation
* Lotus' Developers' Page


Local User Groups

* WALNUT
* Wisconsin Notes User Group
* The User Group (Notes user group in U.K.)
* Charlotte Lotus Notes User Group (in North Carolina)
* St. Louis Domino Notes User Group (in Missouri, USA)
* Washington, DC Notes User Group
* GRANITE (Notes User Group in Chicago)
* NUTS (Notes User Group for Ohio, Kentucky, Indiana)
* Atlanta Lotus Notes Users Group
* New England Domino and Notes Special Interest Group
* Toronto Notes Users Group
* eGLU (Notes user group in India)


Notes R4 Database Samples

The Lotus samples that come with Version 4 don't use the features in Version 4 enough. However, there are several places you can get more samples from:

* ComputerWorks has fully functional (limited record input) demo versions of most of
their applications on their web page.
* New Information Paradigms has placed a demo application named "Millenia" which they wrote with Lotus UK for demonstrating Notes 4 apps design and Notes 4 & IWP at seminars. It is on their web site here.
* [email] Sid Bagali of Parametric has placed a System Inventory example that he put together while learning about Notes V4 features here.
* AppJunction Discussion is a Domino-enabled discussion database.


Notes Related Web Sites

Lotus' Notes Knowledgebase can be queried here. This is a great place to search for known bugs and workarounds that Lotus recommends.

These are all Domino Discussions:
* Lotus Notes Discussions
* Lotus Domino Discussion

Other Sites from Lotus and Iris Associates:
* Lotus Development Corp. Home Page
* Lotus' Developer Central
* Iris Associates (the creators of Notes)
* Developer Central's Sample Images for Domino
* Lotus Enterprise Integration (NotesPump, NotesSQL, etc.)

Other good Notes web sites:
* Scott Nash's Excellent Notes Tour
* Frank Cseh's Notes Page
* European Notes Page
* U. Michigan's Notes Page
* Binary Tree's Domino Knowledgebase
*
Rose Kelleher's (a great book author) Notes Stuff
* Notes Design & Development
* Notes Solutions
* Lotus Notes Job Listings
* Domino Jobs
* Domino Cafe
* Andre Guirard's BP Tools
* Siva's Notes World
* Domino SuperSearch
* DataBeam's Developer Forum
* Tips & Tricks for Lotus Notes and Domino
* PCIS' Notes Usenet Archive Search


Mirrors Sites for the Notes FAQ

The following sites mirror this FAQ site:
* KEY Enterprise Solutions
* Volant Turnpike
* GRS Consult AB


Home *Notes V3 *Notes V4 *Notes/Domino 4.5

Last Modified: January 27, 2000