[comp.sys.mac.hypercard] Setting userLevel at openStack time

tomj@oakhill.UUCP (Tom Johnson) (03/01/90)

I'm haveing a problem that I can't seem to resolve, soooo... I thought I might
just try the net.

Here's the scenario:  I have a stack I developed for internal use. It works
great, does everything it is supposed to do, and is loved by all who use it.
(stroke, stroke, stroke  :>))  I don't want the grungy users munging around
in my pristine scripts, so I decide to set the userLevel to 2 at openStack
time.  I also add a nifty password capability so I can get back to userLevel
5 whenever I want.  I also trap all "set" messages, and if the password
check has not been met, and the keyword "userLevel" is in the "set" message,
just beep, otherwise pass the set on.  Everything works great EXCEPT the
request to set the userLevel to 2 on openStack!  I've tried everything I can
think of:
	1)  use a "send 'set UserLevel to 2' to Hypercard"
	2)  issue a "set userLevel to 2" after tricking the password checker
	3)  every possible variation on the above 2, and in every possible
	    position of the openStack handler.

The "set userLevel to 2" works fine, as long as it is NOT in the openStack
handler.  What's going on?

Particulars:  Hypercard 1.2.2, MacIIcx 8/80, bunches of inits (although I
	      don't believe these are causing any problems).

Any answers out there?

Tom Johnson  (tomj@oakhill.UUCP)

Standard disclaimers apply.

jdevoto@Apple.COM (Jeanne A. E. DeVoto) (03/01/90)

In article <3026@oakhill.UUCP> tomj@oakhill.UUCP (Tom Johnson) writes:
> [...]                I don't want the grungy users munging around
>in my pristine scripts, 

Oh, please. I have yet to see the piece of code that couldn't be
improved.  A wish to protect naive users is commendable, and a valid
reason for hiding scripts; but a reluctance to see one's code sullied
by bugfixes and improvements is not. Furthermore, one rule-of-thumb in
designing user interfaces is that user-settable preferences (such as the
userLevel) should not be changed unless it's required for best functioning
of the stack.

However:
>                          so I decide to set the userLevel to 2 at openStack
>time.  I also add a nifty password capability so I can get back to userLevel
>5 whenever I want.  I also trap all "set" messages, and if the password
>check has not been met, and the keyword "userLevel" is in the "set" message,
>just beep, otherwise pass the set on. 

This is an awful lot of trouble to go to. Why not use the Protect Stack
item to set the lid userlevel to 2? Much simpler, reasonably foolproof.
And it does exactly what your solution does. You also don't have to worry
about cleaning up after your stack when the user exits (I assume you *are*
saving the previous userLevel and restoring it on closeStack?).

>Everything works great EXCEPT the
>request to set the userLevel to 2 on openStack!  I've tried everything I can
>think of:
>	1)  use a "send 'set UserLevel to 2' to Hypercard"
>	2)  issue a "set userLevel to 2" after tricking the password checker
>	3)  every possible variation on the above 2, and in every possible
>	    position of the openStack handler.
>
>The "set userLevel to 2" works fine, as long as it is NOT in the openStack
>handler.  What's going on?

The problem is that the startup message is sent AFTER openStack, rather
than before as one might think. The Home stack's startup handler executes
a routine called getHomeInfo, which among other things sets the userLevel
to the user's preferred level. This means that any preferences set in
a stack's openStack handler are reset to the user's selected preferences
immediately if the stack has been opened by double-clicking.
-- 
====== jeanne a. e. devoto ========================================
 jdevoto@apple.com  |  You may not distribute this article under a
 jdevoto@well.UUCP  |  compilation copyright without my permission.
___________________________________________________________________
 Apple Computer and I are not authorized  |        CI$: 72411,165
 to speak for each other.                 |  AppleLink: SQA.TEST

jdevoto@Apple.COM (Jeanne A. E. DeVoto) (03/06/90)

In article <3048@oakhill.UUCP> tomj@oakhill.UUCP (Tom Johnson) writes:
>...although I didn't specifically state this in my original posting, the
>REASON I want to put some special password protection on the stack is that
>the stack will be shared by MANY people, some of whom have some familiarity
>with Hypercard, but ALL of whom are engineering types that love to tinker.
>Thus, to make sure that this business-oriented stack continiues to perform its
>purpose, it is necessary to add additional protection against unwanted
>changing of the scripts.[...] In the interest of saving ntework bandwith, I
>didn't feel it necessary to explain all of this up front.

While a desire to save bandwidth is commendable, you will find that a complete
statement of the problem will generally net more helpful and varied answers.
In this case, it seems that you do not object to users looking at the scripts,
nor do you particularly want to override their setup preferences (a
particularly bad idea with HyperCard-knowledgeable users, since they often
have a carefully crafted setup and will be annoyed by stacks that interfere
with it).

Anyway, to achieve the goal of preventing script modification, you might
consider setting the cantModify property. This will lock out all changes to
the stack; although users will still have script access at whatever userlevel
they have set up, they won't be able to make changes to the scripts (or
anything else in the stack).

If you need to have users type data in to fields and such (and these
changes need to be saved), you will need to use the userModify property
in conjunction with the cantModify. If both these properties are true,
users will be able to type into fields (assuming the userLevel is at least
2, of course...), but the changes are not permanent as long as cantModify
is true. To ensure that the changes get saved, you can write a short
handler like so:

 on saveChanges
   -- put data that should be saved into variables, e.g.:
   put field "Address" into addressVar
   set the cantModify of this stack to false
   put addressVar into field "Address"
   set the cantModify of this stack to true
 end saveChanges

Your navigation handlers should call saveChanges before they go to any
other card. (You may wish to put a lock screen/unlock screen pair in the
saveChanges handler, since the new data disappears when cantModify is
changed, resulting in mildly unpleasant flickering.) You'll also need
to set the userModify global property to true in your openStack handler.

This approach lets you keep scripts from being modified, without having to
mess with saving and restoring the userLevel, overriding user preferences,
or risking messing up someone else's stack which may depend on a custom
startup handler.

>Thanks for coming to the rescue, Eric, and once again, its is nice to know
>that there are people out there willing to forego destructive criticism
>for constructive criticism.

I'm sure it is.
-- 
====== jeanne a. e. devoto ========================================
 jdevoto@apple.com  |  You may not distribute this article under a
 jdevoto@well.UUCP  |  compilation copyright without my permission.
___________________________________________________________________
 Apple Computer and I are not authorized  |        CI$: 72411,165
 to speak for each other.                 |  AppleLink: SQA.TEST