DIRECTORY Atom USING [ MakeAtom ], BasicTime USING [ FromNSTime, GMT, Now, nullGMT, Period, ToNSTime, Update ], Booting USING [ RegisterProcs, RollbackProc ], Commander USING [ CommandProc, Handle, Register ], CommandTool USING [ NextArgument ], Convert USING [ CardFromRope ], DESFace USING [ CorrectParity, EncryptBlock ], IO, LoganBerry USING [ AttributeType, AttributeValue, Close, DeleteEntry, Error, Open, OpenDB, ReadEntry, WriteEntry ], LoganBerryExtras USING [ IsLocal, RegisterWriteProc, WriteProc ], NameDB USING [ AttributeSeq, Authenticity ], NameDBBackDoor, Process USING [ Detach ], RefID USING [ nullID ], RefTab USING [ Create, Fetch, Ref, Store ], Rope USING [ Equal, Length, ROPE, SkipOver ], RPC USING [ EncryptionKey ], SymTab USING [ Create, Delete, Erase, Fetch, Ref, Store ], UserProfile USING [ Token ], VoiceUtils USING [ NetAddress, NetAddressFromRope, nullNetAddress ] ; NameDBImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, Booting, Commander, CommandTool, Convert, DESFace, IO, LoganBerry, LoganBerryExtras, Process, RefTab, Rope, SymTab, UserProfile, VoiceUtils EXPORTS NameDB, NameDBBackDoor = { ROPE: TYPE= Rope.ROPE; AttributeSeq: TYPE = NameDB.AttributeSeq; -- LoganBerry.Entry = LIST OF [$attribute, value] OpenDB: TYPE = REF OpenDBBody; nullDB: OpenDB = NIL; OpenDBBody: TYPE = RECORD [ db: LoganBerry.OpenDB_RefID.nullID, dbCache: DBCache _ NIL, timeoutCache: BOOL_TRUE, -- TRUE if should time out entries based on timeToLive timeToLive: INT _ 20 -- Seconds duration of NameDB cache entries. ]; Error: PUBLIC ERROR [ec: ATOM, explanation: Rope.ROPE _ NIL] = CODE; DBCache: TYPE = SymTab.Ref; DBHandle: TYPE = RECORD [ -- In case there ever have to be instances dbPrefix: Rope.ROPE, white: OpenDB_nullDB, -- Name/number database blue: OpenDB_nullDB, -- Name/Lark/Workstation/Preferences database red: OpenDB_nullDB, -- GV cache database doCache: BOOL _ TRUE, whiteTTL: INT _ 60*60*4, -- 4 hours cache duration blueTTL: INT _ 20, -- short cache duration redTTL: INT _ 60*60 -- 1 hour cache duration ]; dbHandle: DBHandle; -- There is but one instance now. minQueryInterval: INT _ 60; GetAttributes: PUBLIC PROC[rName: ROPE, key: ATOM_$rname, dbType: ATOM_$white] RETURNS [value: AttributeSeq_NIL] = { ENABLE { UNWIND => NULL; LoganBerry.Error => Error[ec, explanation]; }; RETURN[ReadEntry[db: DBFromType[dbType], key: key, value: rName].attributes]; }; GetAttribute: PUBLIC PROC[ rName: ROPE, attribute: ATOM, default: ROPE_NIL, key: ATOM_$rname] RETURNS [value: ROPE_NIL] = { ENABLE { UNWIND => NULL; LoganBerry.Error => Error[ec, explanation]; }; dbKType: ATOM; dbType: ATOM; openDB: OpenDB; cached: BOOL_FALSE; attributes: AttributeSeq; [dbKType, , openDB] _ WhichDB[key]; IF dbKType#$noProbe THEN { attributes _ ReadEntry[db: openDB, key: key, value: rName].attributes; rName _ FetchAttribute[attributes, $rname, NIL].value; IF rName=NIL THEN RETURN[default]; }; [dbType, , openDB] _ WhichDB[attribute]; SELECT dbType FROM $red => RETURN[GetGVAttribute[rName, attribute, default]]; $noProbe => RETURN[rName]; #dbKType => attributes _ ReadEntry[db: openDB, key: $rname, value: rName].attributes; ENDCASE; value _ FetchAttribute[attributes, attribute, default].value; IF value.Equal["#"] THEN { value _ FetchAttribute[attributes, TAttr[attribute, "time"]].value; value _ FetchAttribute[attributes, TAttr[attribute, (IF value#NIL AND RelTime[value] > 0 THEN "timed" ELSE "untimed")], default].value; }; }; SetAttribute: PUBLIC PROC[rName: ROPE, attribute: ATOM, value: ROPE] = { ENABLE { UNWIND => NULL; LoganBerry.Error => Error[ec, explanation]; }; dbType: ATOM; openDB: OpenDB; attributes: AttributeSeq; previousValue: ROPE; IF value#NIL THEN SELECT attribute FROM $larkhost, $workstationhost => { oldRname: ROPE=GetAttribute[value, $rname, NIL, attribute]; IF oldRname#NIL THEN SetAttribute[rName: oldRname, attribute: attribute, value: NIL]; }; ENDCASE; [dbType, , openDB] _ WhichDB[attribute]; IF dbType=$noProbe THEN RETURN; attributes _ ReadEntry[openDB, $rname, rName, FALSE].attributes; IF attributes=NIL THEN attributes _ LIST[[$rname, rName]]; previousValue _ FetchAttribute[attributes, attribute].value; IF previousValue.Equal[value] THEN RETURN; -- previous was untimed and equal attributes _ StoreAttribute[attributes, attribute, value]; IF previousValue.Equal["#"] THEN { -- Remove the timed values attributes _ StoreAttribute[attributes, TAttr[attribute, "timed"], NIL]; attributes _ StoreAttribute[attributes, TAttr[attribute, "untimed"], NIL]; attributes _ StoreAttribute[attributes, TAttr[attribute, "time"], NIL]; }; LoganBerry.WriteEntry[db: openDB.db, entry: attributes, replace: TRUE]; }; SetAttributeTimed: PUBLIC PROC[ rName: Rope.ROPE, attribute: ATOM, value: Rope.ROPE, time: BasicTime.GMT_BasicTime.nullGMT, interval: INT_0] = { ENABLE LoganBerry.Error => Error[ec, explanation]; dbType: ATOM; keyClass: KeyClass; openDB: OpenDB; attributes: AttributeSeq; untimedValue: Rope.ROPE; wasUntimed: BOOL; IF time=BasicTime.nullGMT THEN time _ BasicTime.Update[BasicTime.Now[], interval]; [dbType, keyClass, openDB] _ WhichDB[attribute]; IF keyClass#$notKey THEN Error[$InvalidAttribute, "SetAttributeTimed cannot be applied to an attribute that is also a key"]; attributes _ ReadEntry[openDB, $rname, rName, FALSE].attributes; -- No trust cache IF attributes=NIL THEN attributes _ LIST[[$rname, rName]]; untimedValue _ FetchAttribute[attributes, attribute].value; wasUntimed _ ~Rope.Equal[untimedValue, "#"]; IF wasUntimed AND untimedValue#NIL THEN attributes _ StoreAttribute[attributes, TAttr[attribute, "untimed"], untimedValue]; attributes _ StoreAttribute[attributes, TAttr[attribute, "timed"], value]; attributes _ StoreAttribute[attributes, TAttr[attribute, "time"], TimeRope[time]]; IF wasUntimed THEN attributes _ StoreAttribute[attributes, attribute, "#"]; LoganBerry.WriteEntry[db: openDB.db, entry: attributes, replace: TRUE]; }; Authenticate: PUBLIC PROC[rName: ROPE, key: RPC.EncryptionKey] RETURNS [authenticity: NameDB.Authenticity_$unknown] = { ENABLE { LoganBerry.Error => Error[ec, explanation]; Error => IF ec = $GVServersDown THEN CONTINUE; }; keyRope: ROPE _ GetGVAttribute[rName, $key, NIL, TRUE, key]; RETURN[SELECT TRUE FROM keyRope=NIL => $nonexistent, keyRope.Equal["?"] => $bogus, ENDCASE => $authentic ]; }; IsAuthenticated: PUBLIC PROC[rName: ROPE] RETURNS [authenticity: NameDB.Authenticity _ $unknown] = { ENABLE { LoganBerry.Error => Error[ec, explanation]; Error => IF ec = $GVServersDown THEN CONTINUE; }; key: ROPE _ GetGVAttribute[rName, $key, NIL]; RETURN[SELECT TRUE FROM key=NIL => $nonexistent, key.Equal["?"] => $perhaps, ENDCASE => $authentic ]; }; HostFromInstance: PUBLIC PROC[instance: Rope.ROPE] RETURNS [VoiceUtils.NetAddress_VoiceUtils.nullNetAddress] = { netAddressAsRope: ROPE = GetAttribute[instance, $connect]; IF netAddressAsRope#NIL THEN RETURN[VoiceUtils.NetAddressFromRope[netAddressAsRope]]; }; nullKey: RPC.EncryptionKey = ALL[0]; GetGVAttribute: PROC[ rName: ROPE, attribute: ATOM, default: ROPE, keySupplied: BOOL_FALSE, encryptionKey: RPC.EncryptionKey_nullKey] RETURNS[value: ROPE_NIL] = { openDB: OpenDB _ DBFromType[$red]; attributes: AttributeSeq; cached: BOOL; [attributes, cached] _ ReadEntry[openDB, $rname, rName]; IF attributes=NIL OR (attribute=$key AND keySupplied AND ~FetchAttribute[attributes, $key, "?"].value.Equal[KeyRope[encryptionKey]]) THEN [attributes, cached] _ GetGVUpdate[rName, keySupplied, encryptionKey]; value _ FetchAttribute[attributes, attribute, default].value; IF ~cached THEN QueueGVUpdate[rName, keySupplied, encryptionKey]; }; GetGVUpdate: PROC[ rName: ROPE, keySupplied: BOOL_FALSE, encryptionKey: RPC.EncryptionKey_nullKey] RETURNS[attributes: AttributeSeq_NIL, cached: BOOL_FALSE] = { }; DeleteGVEntry: PROC[rName: ROPE] RETURNS [nilRope: ROPE_NIL] = { IF dbHandle.white=nullDB OR rName=NIL THEN RETURN; LoganBerry.DeleteEntry[db: DBFromType[$red].db, key: $rname, value: rName]; }; QueueGVUpdate: PROC[ rName: ROPE, keySupplied: BOOL_FALSE, encryptionKey: RPC.EncryptionKey] = TRUSTED { Process.Detach[FORK ForkGVUpdate[rName, keySupplied, encryptionKey]]; }; ForkGVUpdate: PROC[rName: ROPE, keySupplied: BOOL_FALSE, encryptionKey: RPC.EncryptionKey] = { ENABLE Error => CONTINUE; -- Should report it, I guess. [] _ GetGVUpdate[rName, keySupplied, encryptionKey]; }; KeyRope: PUBLIC -- to back door -- PROC[key: RPC.EncryptionKey] RETURNS[keyRope: ROPE] = TRUSTED { encryptedKey: RPC.EncryptionKey; cpKey: RPC.EncryptionKey _ key; halves: LONG POINTER TO RECORD[firstHalf: CARD, secondHalf: CARD] _ LOOPHOLE[LONG[@encryptedKey]]; DESFace.CorrectParity[LOOPHOLE[LONG[@cpKey]]]; DESFace.EncryptBlock[key: LOOPHOLE[cpKey], from: @key, to: LOOPHOLE[halves]]; keyRope _ IO.PutFR["%bB %bB", [cardinal[halves.firstHalf]], [cardinal[halves.secondHalf]]]; }; ReadEntry: PROC[ db: OpenDB, key: LoganBerry.AttributeType, value: LoganBerry.AttributeValue, useCache: BOOL_TRUE] RETURNS [attributes: AttributeSeq_NIL, cached: BOOL_FALSE] = { IF dbHandle.doCache AND useCache THEN IF key=$rname THEN attributes_ReadCache[db, value]; IF attributes#NIL THEN RETURN[attributes, TRUE]; attributes _ LoganBerry.ReadEntry[db: db.db, key: key, value: value].entry; IF dbHandle.doCache AND attributes#NIL THEN IF useCache THEN RecordCache[db, attributes] ELSE DeleteFromCache[db, attributes]; }; FetchAttribute: PUBLIC -- to back door -- PROC[ attributes: AttributeSeq, attribute: ATOM, default: ROPE_NIL] RETURNS [value: ROPE, valueLoc: AttributeSeq_NIL] = { value _ default; FOR aL: AttributeSeq _ attributes, aL.rest WHILE aL#NIL DO IF aL.first.type = attribute THEN RETURN[aL.first.value, aL]; ENDLOOP; }; ExtractAttribute: PUBLIC -- to back door -- PROC[ attributes: AttributeSeq, attribute: ATOM] RETURNS [newAttributes: AttributeSeq_NIL] = { IF attributes=NIL THEN RETURN; IF attributes.first.type=attribute THEN RETURN[attributes.rest]; newAttributes _ attributes; FOR aL: AttributeSeq _ attributes, aL.rest WHILE aL.rest#NIL DO IF aL.rest.first.type # attribute THEN LOOP; aL.rest _ aL.rest.rest; RETURN; ENDLOOP; }; StoreAttribute: PUBLIC -- to back door -- PROC[attributes: AttributeSeq, attribute: ATOM, value: ROPE] RETURNS[newAttributes: AttributeSeq] = { oldLoc: AttributeSeq; IF value=NIL OR value.Length[]=value.SkipOver[skip: "\015\011"] THEN RETURN[ExtractAttribute[attributes, attribute]]; newAttributes _ attributes; oldLoc _ FetchAttribute[attributes, attribute].valueLoc; IF oldLoc#NIL THEN oldLoc.first _ [attribute, value] ELSE newAttributes _ Append[attributes, LIST[[attribute, value]]]; }; Append: PUBLIC -- to back door -- PROC[ a1, a2: AttributeSeq] RETURNS [newAttributes: AttributeSeq] = { IF a2=NIL THEN RETURN[a1]; IF a1=NIL THEN RETURN[a2]; newAttributes _ a1; FOR aL: AttributeSeq _ a1, aL.rest WHILE aL#NIL DO IF aL.rest#NIL THEN LOOP; aL.rest _ a2; RETURN; ENDLOOP; ERROR; }; DBFromType: PROC[dbType: ATOM] RETURNS [openDB: OpenDB _ nullDB] = { IF dbHandle.white=nullDB THEN Open[]; RETURN[SELECT dbType FROM $white => dbHandle.white, $blue => dbHandle.blue, $red => dbHandle.red, ENDCASE => nullDB ]; }; WhichDB: PROC[keyType: ATOM] RETURNS [ dbType: ATOM_$blue, keyClass: KeyClass_$notKey, openDB: OpenDB _ nullDB] = { mer: MapEntry _ NARROW[dbMap.Fetch[keyType].val, MapEntry]; IF mer#NIL THEN { dbType _ mer.dbType; keyClass _ mer.keyClass; }; openDB _ DBFromType[dbType]; }; RelTime: PUBLIC -- to back door -- PROC[ropeTime: ROPE] RETURNS [relativeToNow: INT] = { RETURN[BasicTime.Period[from: BasicTime.Now[], to: BasicTime.FromNSTime[Convert.CardFromRope[ropeTime]]]]; }; TimeRope: PUBLIC -- to back door -- PROC [time: BasicTime.GMT _ BasicTime.nullGMT] RETURNS[nowRope: ROPE] = { IF time = BasicTime.nullGMT THEN time _ BasicTime.Now[]; RETURN[IO.PutFR["%bB", [cardinal[BasicTime.ToNSTime[time]]]]]; }; TAttr: PUBLIC -- to back door -- PROC[attribute: ATOM, prefix: Rope.ROPE] RETURNS [tAttr: ATOM] = { RETURN[Atom.MakeAtom[IO.PutFR["%g.%g", [rope[prefix]], [atom[attribute]]]]]; }; Open: PROC[forceOpen: BOOL_FALSE] = { ENABLE LoganBerry.Error => Error[ec, explanation]; prefixValue: IO.Value _ [rope[dbHandle.dbPrefix]]; IF forceOpen THEN { IF dbHandle.white#nullDB THEN LoganBerry.Close[db: dbHandle.white.db]; IF dbHandle.blue#nullDB THEN LoganBerry.Close[db: dbHandle.blue.db]; IF dbHandle.red#nullDB THEN LoganBerry.Close[db: dbHandle.red.db]; }; dbHandle.white _ LBOpen[IO.PutFR["%gWhitePages.df", prefixValue], dbHandle.whiteTTL]; dbHandle.blue _ LBOpen[IO.PutFR["%gBluePages.df", prefixValue], dbHandle.blueTTL]; dbHandle.red _ LBOpen[IO.PutFR["%gRedPages.df", prefixValue], dbHandle.redTTL, TRUE]; }; LBOpen: PROC[dbName: ROPE, timeToLive: INT, alwaysTimeout: BOOL_FALSE] RETURNS [ openDB: OpenDB] = { openDB _ NEW[OpenDBBody _ []]; openDB.dbCache _ SymTab.Create[case: FALSE]; openDB.db _ LoganBerry.Open[dbName: dbName]; LoganBerryExtras.RegisterWriteProc[ proc: RecordWrite, db: openDB.db, ident: $nameDB, clientData: openDB]; openDB.timeoutCache _ alwaysTimeout OR ~LoganBerryExtras.IsLocal[openDB.db]; openDB.timeToLive _ timeToLive; }; CacheEntry: TYPE = REF CacheEntryBody; CacheEntryBody: TYPE = RECORD [ attributes: AttributeSeq _ NIL, lastValid: BasicTime.GMT _ BasicTime.nullGMT ]; ReadCache: PROC[openDB: OpenDB, keyValue: LoganBerry.AttributeValue] RETURNS[attributes: AttributeSeq_NIL] = { cacheEntry: CacheEntry; IF openDB=NIL OR ~dbHandle.doCache THEN RETURN; cacheEntry _ NARROW[SymTab.Fetch[openDB.dbCache, keyValue].val]; IF cacheEntry=NIL OR (openDB.timeoutCache AND BasicTime.Period[from: cacheEntry.lastValid, to: BasicTime.Now[]] > openDB.timeToLive) THEN RETURN; RETURN[cacheEntry.attributes]; }; RecordCache: PROC[openDB: OpenDB, attributes: AttributeSeq] = { cacheEntry: CacheEntry; rName: ROPE _ FetchAttribute[attributes, $rname, NIL].value; IF openDB=NIL OR rName = NIL THEN RETURN; cacheEntry _ NARROW[SymTab.Fetch[openDB.dbCache, rName].val]; IF cacheEntry = NIL THEN { cacheEntry _ NEW[CacheEntryBody _ []]; [] _ SymTab.Store[openDB.dbCache, rName, cacheEntry]; }; cacheEntry.attributes _ attributes; cacheEntry.lastValid _ BasicTime.Now[]; }; RecordWrite: -- INTERNAL -- LoganBerryExtras.WriteProc = { DeleteFromCache[NARROW[clientData], entry]; }; DeleteFromCache: -- INTERNAL -- PROC[openDB: OpenDB, attributes: AttributeSeq] = { rName: ROPE; IF attributes=NIL OR openDB=NIL THEN RETURN; rName _ FetchAttribute[attributes, $rname, NIL].value; IF rName#NIL THEN []_SymTab.Delete[openDB.dbCache, rName]; }; CmdDBOpen: Commander.CommandProc = { arg: ROPE _ CommandTool.NextArgument[cmd]; IF arg#NIL THEN dbHandle.dbPrefix _ arg; Open[TRUE]; }; CmdDBDetails: Commander.CommandProc = { DoDetails[cmd, CommandTool.NextArgument[cmd]]; }; DoDetails: PROC[cmd: Commander.Handle, rName: ROPE] = { DoSomeDetails[cmd, rName, $white, TRUE]; DoSomeDetails[cmd, rName, $blue]; DoSomeDetails[cmd, rName, $red]; IO.PutChar[cmd.out, '\n]; }; DoSomeDetails: PROC[ cmd: Commander.Handle, rName: ROPE, dbType: ATOM, includeRName: BOOL_FALSE] = { attributes: AttributeSeq _ GetAttributes[rName, $rname, dbType]; IF attributes#NIL AND ~includeRName THEN attributes _ attributes.rest; FOR attr: AttributeSeq _ attributes, attr.rest WHILE attr#NIL DO IO.PutF[cmd.out, "%g: %g\n", [atom[attr.first.type]], [rope[attr.first.value]]]; ENDLOOP; }; CmdLarkDebug: Commander.CommandProc = { larkNumber: ROPE _ CommandTool.NextArgument[cmd]; instance: ROPE _ CommandTool.NextArgument[cmd]; IF instance=NIL THEN instance _ UserProfile.Token[key: "LarktestInstance", default: "Einstein.lark"]; DoOperate[cmd, larkNumber, "D", instance]; }; CmdLarkOperate: Commander.CommandProc = { larkNumber: ROPE _ CommandTool.NextArgument[cmd]; instance: ROPE _ CommandTool.NextArgument[cmd]; IF instance=NIL THEN instance _ UserProfile.Token[key: "ThrushClientServerInstance", default: "Strowger.lark"]; DoOperate[cmd, larkNumber, "O", instance]; }; DoOperate: PROC[cmd: Commander.Handle, larkNumber: ROPE, mode: ROPE, instance: ROPE] = { rName: ROPE; IF larkNumber=NIL THEN RETURN; larkNumber _ IO.PutFR["173#%g#", [rope[larkNumber]]]; rName _ GetAttribute[larkNumber, $rname, NIL, $larkhost]; IF rName=NIL THEN RETURN; SetAttribute[rName, $mode, mode]; SetAttribute[rName, $instance, instance]; DoDetails[cmd, rName]; }; CmdLarkOwner: Commander.CommandProc = { larkNumber: ROPE _ CommandTool.NextArgument[cmd]; newOwner: ROPE _ CommandTool.NextArgument[cmd]; IF larkNumber=NIL OR newOwner=NIL THEN RETURN; larkNumber _ IO.PutFR["173#%g#", [rope[larkNumber]]]; SetAttribute[newOwner, $larkhost, larkNumber]; DoDetails[cmd, newOwner]; }; CmdLarkDBGet: Commander.CommandProc = { rName: ROPE _ CommandTool.NextArgument[cmd]; attribute: ROPE _ CommandTool.NextArgument[cmd]; value: ROPE; IF rName=NIL OR attribute=NIL THEN RETURN; value _ GetAttribute[rName, Atom.MakeAtom[attribute]]; IO.PutF[cmd.out, "Name: %g\n%g: %g\n\n", [rope[rName]], [rope[attribute]], [rope[value]]]; }; CmdLarkDBSet: Commander.CommandProc = { rName: ROPE _ CommandTool.NextArgument[cmd]; attribute: ROPE _ CommandTool.NextArgument[cmd]; value: ROPE _ CommandTool.NextArgument[cmd]; IF rName=NIL OR attribute=NIL THEN RETURN; SetAttribute[rName, Atom.MakeAtom[attribute], value]; DoDetails[cmd, rName]; }; CmdDBFlush: Commander.CommandProc = { IF dbHandle.white#NIL THEN SymTab.Erase[dbHandle.white.dbCache]; IF dbHandle.blue#NIL THEN SymTab.Erase[dbHandle.blue.dbCache]; IF dbHandle.red#NIL THEN SymTab.Erase[dbHandle.red.dbCache]; }; CmdGVUpdate: Commander.CommandProc = { rName: ROPE _ CommandTool.NextArgument[cmd]; []_DeleteGVEntry[rName]; DoDetails[cmd, rName]; }; ForceOpenOnNextCall: Booting.RollbackProc = { dbHandle.white _ dbHandle.red _ dbHandle.blue _ nullDB; }; KeyClass: TYPE = { primary, secondary, notKey }; MapEntry: TYPE = REF MER; MER: TYPE = RECORD [ dbType: ATOM, keyClass: KeyClass_$notKey ]; dbMap: RefTab.Ref _ RefTab.Create[]; [] _ dbMap.Store[$rname, NEW[MER _ [$noProbe, $primary]]]; [] _ dbMap.Store[$name, NEW[MER _ [$white, $secondary]]]; [] _ dbMap.Store[$fnm, NEW[MER _ [$white, $secondary]]]; [] _ dbMap.Store[$rgnm, NEW[MER _ [$white, $secondary]]]; [] _ dbMap.Store[$fstnm, NEW[MER _ [$white, $secondary]]]; [] _ dbMap.Store[$officenumber, NEW[MER _ [$white]]]; [] _ dbMap.Store[$homenumber, NEW[MER _ [$white]]]; [] _ dbMap.Store[$officeaddress, NEW[MER _ [$white]]]; [] _ dbMap.Store[$homeaddress, NEW[MER _ [$white]]]; [] _ dbMap.Store[$larkhost, NEW[MER _ [$blue, $secondary]]]; [] _ dbMap.Store[$workstationhost, NEW[MER _ [$blue, $secondary]]]; [] _ dbMap.Store[$dotune, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$instance, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$interface, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$mode, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$multiring, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$program, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$ringmode, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$ringtune, NEW[MER _ [$blue]]]; [] _ dbMap.Store[$connect, NEW[MER _ [$red]]]; [] _ dbMap.Store[$key, NEW[MER _ [$red]]]; [] _ dbMap.Store[$authenticity, NEW[MER _ [$red]]]; -- useful only for IsAuthenticated dbHandle.dbPrefix _ UserProfile.Token["ThrushSunDBPrefix", "/Growler-SUN///Strowger/"]; Commander.Register["NameDBOpen", CmdDBOpen, "Specify location of system databases. Usage: NameDBOpen Example: NameDBOpen /Growler-SUN///Strowger/ Example: NameDBOpen /Strowger.lark//Strowger/ Example: NameDBOpen ///Users/self.pa/ (first example is the default)\n"]; Commander.Register["NameDBDetails", CmdDBDetails, "Print entire merged DB listing. Usage: NameDBDetails \n"]; Commander.Register["LarkDebug", CmdLarkDebug, "Tune Lark into development server, debug mode. Usage: LarkDebug [] Example: LarkDebug 110 (default instance is UserProfile.LarkTestInstance[]) Example: LarkDebug 110 Curie.lark\n"]; Commander.Register["LarkOperate", CmdLarkOperate, "Tune Lark into operational server, operational mode. Usage: LarkOperate [] Example: LarkOperate 110 (default instance is UserProfile.ThrushClientServerInstance[]) Example: LarkOperate 110 Curie.lark\n"]; Commander.Register["LarkOwner", CmdLarkOwner, "Change assignment of Lark to user. Usage: LarkOwner Example: LarkOwner 155 Swinehart.pa\n"]; Commander.Register["NameDBSet", CmdLarkDBSet, "Change Name database attribute. Usage: NameDBSet Example: NameDBSet Swinehart.pa ringmode S\n"]; Commander.Register["NameDBGet", CmdLarkDBGet, "Query Name database attribute. Usage: NameDBGet Example: NameDBGet Swinehart.pa ringmode\n"]; Commander.Register["NameDBFlushCache", CmdDBFlush, "Flush local DB cache. Usage: NameDBFlushCache\n"]; Commander.Register["NameDBGVUpdate", CmdGVUpdate, "Restore GV values from Grapevine. Usage: NameDBGVUpdate Example: NameDBGVUpdate Curie.lark\n"]; Booting.RegisterProcs[r: ForceOpenOnNextCall]; }. €NameDBImpl.Mesa Copyright Σ 1987, 1990 by Xerox Corporation. All rights reserved. Last modified by Swinehart, October 4, 1989 5:15:47 pm PDT Polle Zellweger (PTZ) August 23, 1990 9:18:26 pm PDT Vin, July 24, 1990 1:24 pm PDT Lock as little as possible Data Mostly just repeats LoganBerry errors. conversation: RPC.Conversation_RPC.unencrypted, Don't query Grapevine about any given value any more frequently. conversationLevel: RPC.ConversationLevel _ ECB; Procedures exported to NameDB If key#rname, acquire the rname If attribute is not in the same entry, use rName to get the entry it's in. Obtain the specified attribute If we're dealing with a timed value, select one of timed.attribute and untimed.attribute These secondary keys must be unique. Cancel any previous values. Can't alter primary key! And deletion of entire entries is done by hand. Don't trust cached values for write! Grapevine update info: GVNames.Outcome; openDB: OpenDB _ DBFromType[$red]; connect: ROPE; changed: BOOL_FALSE; keyRope: ROPE_NIL; oldKeyRope: ROPE_NIL; [info, connect] _ GVNames.GetConnect[rName]; SELECT info FROM individual => IF connect=NIL OR connect.Length[]=0 THEN connect _ "?"; group, notFound => connect _ DeleteGVEntry[rName]; wrongServer, allDown => Error[$GVServersDown, "All GV servers down"]; protocolError => Error[$GVNamesProtocolViolation, "GV Names protocol violation"]; ENDCASE => Error[$GVNamesProtocolViolation, "Unknown return code"]; IF connect=NIL THEN RETURN; IF keySupplied THEN { SELECT GVNames.AuthenticateKey[rName, encryptionKey] FROM group, notFound => keyRope _ DeleteGVEntry[rName]; individual => keyRope _ KeyRope[encryptionKey]; protocolError => Error[$GVNamesProtocolViolation, "GV Names protocol violation"]; wrongServer, allDown => Error[$GVServersDown, "All GV servers down"]; badPwd => keyRope _ "?"; ENDCASE => Error[$GVNamesProtocolViolation, "Unknown return code"]; IF keyRope=NIL THEN RETURN; -- Hmmm; individual existed for connect, but not now! }; attributes _ ReadEntry[openDB, $rname, rName].attributes; -- accept cached value -- attributes _ ReadEntry[openDB, $rname, rName, FALSE].attributes; IF attributes=NIL THEN attributes _ LIST[[$rname, rName]]; IF ~connect.Equal[FetchAttribute[attributes, $connect, NIL].value] THEN { DeleteFromCache[openDB, attributes]; changed _ TRUE; attributes _ StoreAttribute[attributes, $connect, connect]; }; oldKeyRope _ FetchAttribute[attributes, $key, NIL].value; IF oldKeyRope=NIL AND keyRope=NIL THEN { DeleteFromCache[openDB, attributes]; changed _ TRUE; attributes _ StoreAttribute[attributes, $key, "?"]; } ELSE IF keyRope#NIL AND ~keyRope.Equal[oldKeyRope] AND ~keyRope.Equal["?"] THEN { DeleteFromCache[openDB, attributes]; changed _ TRUE; attributes _ StoreAttribute[attributes, $key, keyRope]; }; IF changed THEN LoganBerry.WriteEntry[ db: dbHandle.red.db, entry: attributes, replace: TRUE]; RecordCache[openDB, attributes]; cached _ TRUE; Utilities Entry caching Can't really be INTERNAL, because sometimes called from registered procedures, but always with monitor locked! Shell commands [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [clientData: REF ANY] Mappings rname is handled specially whitePages; names, public addresses&numbers bluePages; private voice system mappings Blue is also the default for unknown attributes, so that we can extend the private mappings without recompiling this table. redPages; cached Grapevine mappings Initialization Default prefix value. Polle Zellweger (PTZ) July 19, 1990 3:06:43 pm PDT Remove Pup dependencies: change to LoganBerry access via Sun RPC, remove conversation from DBHandle record. changes to: DIRECTORY, DBHandle, SetAttribute, SetAttributeTimed, GetGVUpdate, DeleteGVEntry, ReadEntry, Open, LBOpen, ForceOpenOnNextCall, dbHandle, dbHandle, Commander Polle Zellweger (PTZ) July 21, 1990 9:27:46 pm PDT More Pup dependencies: remove references to GVNames. changes to: DIRECTORY, NameDBImpl, GetGVUpdate Polle Zellweger (PTZ) August 23, 1990 9:18:27 pm PDT changes to: DIRECTORY, NameDBImpl, HostFromInstance, GetGVUpdate, dbHandle Κg˜šœ™IcodešœB™BJšœ:™:K™4K™—J˜šΟk ˜ Jšœœ˜Jšœ œœ+˜LJšœœ!˜.Jšœ œ#˜2Jšœ œ˜#Jšœœ˜Jšœœ!˜.Jšœ˜Jšœ œc˜sJšœœ+˜AJ˜,J˜Jšœœ ˜Jšœœ ˜Jšœœ˜+Jšœœœ ˜-Jšœœ˜Jšœœ.˜:Jšœ œ ˜Jšœ œ3˜CJ˜J˜—šΟn œœ˜J™JšœEœV˜€šœ˜"J˜——™J™Jšœœœ˜JšœœΟcΠckŸ˜[šœœœ ˜Jšœœ˜šœ œœ˜J˜#Jšœ˜JšœœœŸ6˜OJšœ œŸ,˜AJ˜——J˜š œœœœœœœ˜DJšœ&™&—J˜Jšœ œ˜J˜šœ œœŸ*˜DJšœœ˜Jšœœœ ™/JšœŸ˜-JšœŸ-˜BJšœŸ˜(Jšœ œœ˜Jšœ œ Ÿ˜2Jšœ œŸ˜*Jšœœ Ÿ˜,J˜—Jšœ5˜5J˜šœœ˜Jšœ@™@—Jšœœœ™/J˜—™J˜š ž œœœœœœ˜NJšœœ˜%Jšœœœ0˜GJšœG˜MJ˜J™—šž œœœ˜Jš œœ œ œœœ˜BJšœ œ˜Jšœœœ0˜GJšœ œ˜Jšœœ˜ J˜Jšœœœ˜J˜J˜J™Jšœ#˜#šœœ˜J˜FJšœ+œ˜6Jšœœœœ ˜"J˜J˜—J™JJšœ(˜(šœ˜Jšœœ,˜:Jšœ œ˜JšœU˜UJšœ˜J˜—J™Jšœ=˜=J˜J™Xšœœ˜JšœC˜C˜3Jš œœœœœ œ˜S—J˜—J˜J˜—š ž œœœœ œ œ˜HJšœœœ0˜GJšœœ˜ J˜Jšœ˜Jšœœ˜š œœœœ ˜'˜ J™AJšœ œœ ˜;Jšœ œ˜Jšœ;œ˜@J˜—Jšœ˜—J˜(šœœœ˜JšœI™I—šœ.œ ˜@Jšœ$™$—Jšœ œœœ˜:J˜Jšœ1˜8šœ˜J˜+Jšœ œœœ˜.J˜—Jšœ œœœ˜<šœœœ˜Jšœœ˜Jšœ˜Jšœ˜J˜—J˜J˜—šžœ œœ˜)Jšœ3˜:šœ˜J˜+Jšœ œœœ˜.J˜—Jšœœœ˜-šœœœ˜Jšœœ˜Jšœ˜Jšœ˜J˜—J˜J˜—šžœ œœ˜2Jšœ6˜=Jšœœ$˜:šœœ˜Jšœ2˜8—J˜J˜——™J˜Jšœ œœ˜$J˜šžœœ˜Jšœœ œ œ˜,Jšœ œœœ˜BJšœœœ˜J˜"J˜Jšœœ˜ J˜8šœ œ˜šœœ ˜#JšœL˜P—JšœF˜F—Jšœ=˜=Jšœ œ2˜AJ˜J˜—šž œœ˜Jš œœœœœ˜OJšœœ œœ˜=J™J™"Jšœ œ™Jšœ œœ™Jšœ œœ™Jšœ œœ™Jšœ,™,šœ™Jš œœ œœœ™FJšœ2™2J™EJšœQ™QJšœ<™C—Jšœ œœœ™šœ œ™šœ/™9Jšœ2™2J™/JšœQ™QJ™EJ™Jšœ<™C—Jš œ œœœŸ5™QJ™—Jšœ:ŸΟtŸ‘™RJšœ1œ ™CJšœ œœœ™:šœ5œ œ™IJ™$Jšœ œ@™N—Jšœ.œ™9š œ œœ œœ™(J™$Jšœ œ7™E—š œœ œœœœ™QJ™$Jšœ œ<™J—šœ œ™&Jšœ1œ™7—J™ Jšœ œ™J˜J˜—š ž œœœœ œœ˜@Jš œœœœœ˜2JšœK˜KJ˜J˜—šž œœ˜Jš œœœœœœ˜SJ•StartOfExpansionT[q: MBQueue.Queue, proc: PROC [...], data: REF ANY, immediate: BOOL _ FALSE]šœœ2˜EJ˜J˜—š ž œœœœœœ˜^Jšœ œŸ˜7Jšœ4˜4J˜J˜—šžœœŸœœœœ œœ˜bJšœœ˜ Jšœœ˜š œœœœœ œœ˜CJšœœ˜—Jšœœœ ˜.Jšœœœ ˜MJšœ œO˜[J˜—J˜—™ J™šž œœ˜Jšœ*˜*Jšœ,œœ˜6Jšœœ œœ˜?šœœ ˜%Jšœ œ!˜3—Jš œ œœœ œ˜0J˜Kšœœ œ˜+Jšœ œœ!˜R—J˜—J˜šžœœŸœœ˜/Jšœ%œ œœ˜=Jšœ œœ˜5J˜šœ(œœ˜:Jšœœœœ˜F—J˜J˜—šžœœŸœœ˜1Jšœ%œ˜*Jšœœ˜-Jšœ œœœ˜Jšœ!œœ˜@J˜šœ(œ œ˜?Jšœ œ˜,J˜Jšœ˜Jšœ˜—J˜J˜—š žœœŸœœ&œ œ˜fJšœ!˜(J˜šœœœ1˜DJšœ*˜0—J˜J˜8šœœœ"˜4Jšœ$œ˜B—J˜J˜—šžœœŸœœ˜'Jšœ˜Jšœ"˜)Jšœœœœ˜Jšœœœœ˜J˜šœ œœ˜2Jšœ œœœ˜J˜ Jšœ˜Jšœ˜—Jšœ˜J˜—J™šž œœ œœ˜DJšœœ˜%šœœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜Jšœ˜—J˜J˜—šžœœ œ˜šœ˜ Jšœœ@˜L—Jšœœ%˜;šœœœ˜Jšœ˜Jšœ˜J˜—J˜J˜J˜—šžœœŸœœ œœœ˜Xšœ(˜.Jšœ;˜;J˜J˜——šžœœŸœœœœ œ˜mJšœœ˜8Jšœœ5˜>J˜J˜—šžœœŸœœ œœœ œ˜cJšœœ8˜OJ˜—šžœœ œœ˜%Jšœ,˜2Jšœ œ#˜2šœ œ˜–8[conv: LoganBerry.Conv _ NIL, db: LoganBerry.OpenDB]šœ˜Jšœ(˜(—–8[conv: LoganBerry.Conv _ NIL, db: LoganBerry.OpenDB]šœ˜Jšœ'˜'—–8[conv: LoganBerry.Conv _ NIL, db: LoganBerry.OpenDB]šœ˜Jšœ&˜&—J˜—Jšœœ;˜UJšœœ9˜RJšœœ7œ˜UJ˜J˜—šžœœ œœœœœ˜PJšœ˜Jšœ œ˜Jšœ%œ˜,J˜,˜#J˜F—Jšœ$œ&˜LJšœ˜J˜J˜——™ J™J–L -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šœ œœ˜&šœœœ˜Jšœœ˜Jšœœ˜,Jšœ˜J˜—–L -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šž œœ5˜DJšœœ˜)J˜Jš œœœœœ˜/Jšœ œ-˜@šœ œœ˜-šœV˜VJšœœ˜ ——Jšœ˜J˜J˜—–L -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šž œœ.˜?J˜Jšœœ&œ˜Jšœœœ$˜™J—K™K™—…—Q²ƒ½