<> <> <> <> <> <> <> <> <> <<>> DIRECTORY Atom USING[ GetPName ], AuthenticationP14V2 USING[ Problem, CallProblem ], BasicTime USING[ FromNSTime, GetClockPulses, GMT, Now, Period, Pulses, PulsesToSeconds, ToNSTime, UnpackedPeriod, UnpackPeriod ], CHEntriesP0V0, CHOpsP2V3 USING [ItemObject], Convert USING[ CardFromRope, Error, RopeFromCard, RopeFromInt, RopeFromTime, RopeFromXNSAddress, XNSAddressFromRope, XNSHostFromRope ], GluePruneHacks USING [CacheEntry, DomainsForServer, ExposeErrorCode, RopeList], IO USING[ PutChar, PutF, PutF1, PutRope ], MaintainDefs USING[ CmdButton, Level, MyData, MyDataObject, RetrieveProc, What ], MaintainProcs USING[ ChangeLooksProc ], MaintainMisc USING[ CallForItems, EnumGroups, EnumIndividuals, Plural, Verify ], MaintainNS, Process USING[Pause, SecondsToTicks], Real USING[Fix], Rope USING[ Cat, Concat, Equal, Find, FindBackward, Index, Length, Replace, ROPE, Substr ], XNS USING[ Address, Host, unknownAddress, unknownHost, unknownSocket ], XNSAuth USING[ AuthenticationError, CallError, ChangeMyPasswords, CreateSimpleKey, CreateStrongKey, DeleteSimpleKey, DeleteStrongKey, GetIdentityDetails, Identity, SimpleKeyFromPassword, StrongKeyFromPassword], XNSCH USING[ Add, AddAlias, AddGroupProperty, AddItemProperty, AddMember, AddSelf, ChangeItemProperty, Conversation, Delete, DeleteAlias, DeleteMember, DeleteProperty, DeleteSelf, ElementStreamProc, Enumerate, EnumerateDomains, EnumerateOrganizations, Error, ErrorCode, GetProperties, InitiateConversation, IsMember, IsMemberClosure, Item, ListAliases, ListMembers, Lookup, LookupAddressFromRope, LookupItemProperty, Name, Properties, RopeFromItem, TerminateConversation, Which], XNSCHACL USING[ AccessList, AddMemberToPropertyACL, DeleteMemberFromPropertyACL, ListMembersOfPropertyACL], XNSCHItemOps USING[AddressListFromItem, BoolFromItem, Card32FromItem, Card16IntoItem, Card32IntoItem, CreateNewItem, Error, ItemFromAddressList, ItemFromCard16, ItemFromName, ItemFromRope, NameListFromItem, NameFromItem, NameIntoItem], XNSCHName USING[ FieldTooLong, NameFromRope, RopeFromName]; MaintainNSImpl: CEDAR MONITOR LOCKS d USING d: MyData IMPORTS Atom, BasicTime, Convert, GluePruneHacks, IO, MaintainDefs, MaintainMisc, Process, Real, Rope, XNSAuth, XNSCH, XNSCHACL, XNSCHItemOps, XNSCHName EXPORTS MaintainNS = { OPEN CHEntriesP0V0; ROPE: TYPE = Rope.ROPE; MyData: TYPE ~ MaintainDefs.MyData; MyDataObject: TYPE ~ MaintainDefs.MyDataObject; What: TYPE ~ MaintainDefs.What; Name: TYPE = XNSCH.Name; NameRef: TYPE = REF Name; NameList: TYPE = LIST OF NameRef; Item: TYPE = XNSCH.Item; AccessList: TYPE = XNSCHACL.AccessList; Identity: TYPE = XNSAuth.Identity; PropType: TYPE = {unknown, group, rope, name, addressList, authenticationLevel, userData, mailboxInfo}; Property: TYPE = CARD32; <<******** Enquiry operations ******** -->> DoCommand: PUBLIC PROC [d: MyData, cb: MaintainDefs.CmdButton, name, args: ROPE] = { SELECT cb.cmd FROM type, isMember => DoTypeCommand[d, cb, name, args]; set, add, remove, misc => DoUpdateCommand[d, cb, name, args]; ENDCASE => ERROR; }; DoEnumerate: PUBLIC PROC [d: MyData, cb: MaintainDefs.CmdButton, pattern, args: ROPE] = { Enumerate: PROC [d: MyData, cb: MaintainDefs.CmdButton, pattern, args: ROPE] = { AddNameToOrgList: PROC [name: Name] = { nr: NameRef ¬ NEW[Name ¬ name]; orgNameList ¬ CONS[nr, orgNameList]; nOrganizations ¬ SUCC[nOrganizations]; IF d.verbose THEN d.out.PutChar['.]; }; AddNameToDomainList: PROC [name: Name] = { nr: NameRef ¬ NEW[Name ¬ name]; domainNameList ¬ CONS[nr, domainNameList]; nDomains ¬ SUCC[nDomains]; IF d.verbose THEN d.out.PutChar['.]; }; AddNameToFullList: PROC [name: Name] = { nr: NameRef ¬ NEW[Name ¬ name]; fullNameList ¬ CONS[nr, fullNameList]; nNames ¬ SUCC[nNames]; }; ReverseList: PROC [original: NameList] RETURNS[newList: NameList]= { FOR list: NameList ¬ original, list.rest UNTIL list = NIL DO newList ¬ CONS[list.first, newList]; ENDLOOP; }; startTime: BasicTime.GMT; patternName, pat: Name; wildcardInAnyField, wildcardInObject, wildcardInDomain, wildcardInOrganization: BOOL; orgNameList, domainNameList, fullNameList: NameList ¬ NIL; eC: XNSCH.ErrorCode; eW: XNSCH.Which; problems: BOOL ¬ FALSE; fieldTooLong: BOOL ¬ FALSE; patternName ¬ XNSCHName.NameFromRope[pattern ! XNSCHName.FieldTooLong => {fieldTooLong ¬ TRUE; RESUME;}]; wildcardInObject ¬ Rope.Find[patternName.object, "*"] >= 0; wildcardInDomain ¬ Rope.Find[patternName.domain, "*"] >= 0; wildcardInOrganization ¬ Rope.Find[patternName.organization, "*"] >= 0; wildcardInAnyField ¬ wildcardInObject OR wildcardInDomain OR wildcardInOrganization; <> IF ~wildcardInAnyField AND cb.what # matches THEN { DoCommand[d, cb, pattern, args]; RETURN; }; <> pat ¬ patternName; startTime ¬ BasicTime.Now[]; IF d.verbose THEN d.out.PutF1["\n[Starting name expansion of \"%g\"]", [rope[pattern]]]; IF ~wildcardInOrganization THEN AddNameToOrgList[pat] ELSE { XNSCH.EnumerateOrganizations[c, pat, AddNameToOrgList ! XNSCH.Error => { eC ¬ code; eW ¬ which; problems ¬ TRUE; d.out.PutF["\n=> Error: %g (\"%g\")\n", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]], [rope[XNSCHName.RopeFromName[pat]]]]; CONTINUE; }]; orgNameList ¬ ReverseList[orgNameList]; }; FOR thisOrg: NameList ¬ orgNameList, thisOrg.rest UNTIL (thisOrg = NIL OR d.stop) DO domainNameList ¬ NIL; pat.organization ¬ thisOrg.first.organization; pat.domain ¬ patternName.domain; IF d.verbose THEN d.out.PutF1["\n[Org: \"%g\"]", [rope[pat.organization]]]; IF ~wildcardInDomain THEN AddNameToDomainList[pat] ELSE { XNSCH.EnumerateDomains[c, pat, AddNameToDomainList ! XNSCH.Error => { nOrganizationProblems ¬ nOrganizationProblems+1; eC ¬ code; eW ¬ which; problems ¬ TRUE; d.out.PutF["\n=> Error: %g (\"%g\")\n", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]], [rope[XNSCHName.RopeFromName[pat]]]]; CONTINUE; }]; domainNameList ¬ ReverseList[domainNameList]; }; FOR thisDomain: NameList ¬ domainNameList, thisDomain.rest UNTIL (thisDomain = NIL OR d.stop) DO firstObjectInDomain: BOOL ¬ TRUE; prop: Property; host: XNS.Host; atom: ATOM; IF cb.what = matches THEN atom ¬ NARROW[d.cmdData]; fullNameList ¬ NIL; pat.organization ¬ thisDomain.first.organization; pat.domain ¬ thisDomain.first.domain; pat.object ¬ patternName.object; IF d.verbose THEN d.out.PutF["\n [Domain: \"%g:%g\"]", [rope[pat.domain]], [rope[pat.organization]]]; IF cb.what = matches THEN prop ¬ PropertyFromAtom[atom, d]; IF cb.what = matches AND atom # $GroupsAndUsers THEN { d.out.PutF1["(matching: %g) ... ", [rope[GetPropertyInfo[prop].shortLabel]]]; XNSCH.Enumerate[c, pat, prop, AddNameToFullList ! XNSCH.Error => { nDomainProblems ¬ nDomainProblems+1; eC ¬ code; eW ¬ which; problems ¬ TRUE; d.out.PutF["\n=> Error: %g (\"%g\")\n", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]], [rope[XNSCHName.RopeFromName[pat]]]]; CONTINUE; }]; } ELSE { IF MaintainMisc.EnumGroups[cb] THEN XNSCH.Enumerate[c, pat, userGroup, AddNameToFullList ! XNSCH.Error => { nDomainProblems ¬ nDomainProblems+1; eC ¬ code; eW ¬ which; problems ¬ TRUE; d.out.PutF["\n=> Error: %g (\"%g\")\n", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]], [rope[XNSCHName.RopeFromName[pat]]]]; CONTINUE; }]; IF MaintainMisc.EnumIndividuals[cb] THEN XNSCH.Enumerate[c, pat, user, AddNameToFullList ! XNSCH.Error => { nDomainProblems ¬ nDomainProblems+1; eC ¬ code; eW ¬ which; problems ¬ TRUE; d.out.PutF["\n=> Error: %g (\"%g\")\n", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]], [rope[XNSCHName.RopeFromName[pat]]]]; CONTINUE; }]; }; fullNameList ¬ ReverseList[fullNameList]; IF cb.what = matches AND prop = addressList THEN host ¬ HostAddressFromSelection[d]; FOR thisName: NameList ¬ fullNameList, thisName.rest UNTIL (thisName = NIL OR d.stop) DO IF cb.what = matches THEN { name: Name ¬ thisName.first­; IF prop # addressList OR host = XNS.unknownHost OR MatchHostAddressForObject[host, name] THEN { IF ~d.firstTime THEN d.out.PutRope[", "] ELSE d.firstTime ¬ FALSE; d.out.PutF1["\"%g\"", [rope[XNSCHName.RopeFromName[name]]]]; }; LOOP; }; IF firstObjectInDomain THEN { IF d.verbose THEN d.out.PutChar['\n]; firstObjectInDomain ¬ FALSE; }; DoCommand[d, cb, XNSCHName.RopeFromName[thisName.first­], args]; ENDLOOP; ENDLOOP; ENDLOOP; IF nNames > 1 OR nDomains > 1 OR nOrganizations > 1 THEN { d.out.PutF["\n(%g %g", [cardinal[nNames]], [rope[MaintainMisc.Plural["name", "names", nNames]]]]; IF nDomains > 1 OR nOrganizations > 1 THEN d.out.PutF[" in %g %g", [cardinal[nDomains]], [rope[MaintainMisc.Plural["domain", "domains", nDomains]]]]; IF nOrganizations > 1 THEN d.out.PutF[" in %g %g", [cardinal[nOrganizations]], [rope[MaintainMisc.Plural["organization", "organizations", nOrganizations]]]]; d.out.PutRope[" enumerated."]; IF nDomainProblems > 0 OR nOrganizationProblems > 0 THEN { d.out.PutRope[" Problems with "]; d.out.PutF["%g %g and", [cardinal[nDomainProblems]], [rope[MaintainMisc.Plural["domain", "domains", nDomainProblems]]]]; d.out.PutF[" %g %g.)", [cardinal[nOrganizationProblems]], [rope[MaintainMisc.Plural["organization", "organizations", nOrganizationProblems]]]]; } ELSE d.out.PutChar[')]; }; IF d.verbose THEN d.out.PutF["\n[Start: %g, Stop: %g]", [rope[Convert.RopeFromTime[startTime]]], [rope[Convert.RopeFromTime[BasicTime.Now[]]]]]; }; c: XNSCH.Conversation ¬ XNSCH.InitiateConversation[d.identity, d.conversationAddress]; nNames, nDomains, nOrganizations: CARD ¬ 0; nDomainProblems, nOrganizationProblems: CARD ¬ 0; Enumerate[d, cb, pattern, args]; XNSCH.TerminateConversation[c]; }; DoForEachArgument: PROC [d: MyData, c: XNSCH.Conversation, proc: PROC[Name, ROPE, Name, ROPE, BOOL], check: BOOL ¬ TRUE, doDisting: BOOL ¬ TRUE, leader: ROPE ¬ "\n"] = { FOR argList: LIST OF ROPE ¬ d.argList, argList.rest WHILE argList # NIL DO name, distingName: Name; nameRope, distingNameRope, thisArg: ROPE; problems: BOOL; thisArg ¬ argList.first; name ¬ XNSCHName.NameFromRope[thisArg ! XNSCHName.FieldTooLong => RESUME]; nameRope ¬ XNSCHName.RopeFromName[name]; IF doDisting THEN [distingName, problems, , ] ¬ DistinguishedName[name, c] ELSE problems ¬ TRUE; IF ~problems THEN distingNameRope ¬ XNSCHName.RopeFromName[distingName]; IF check AND ~CheckName[name] THEN { IF MaintainMisc.Verify[d] THEN { d.out.PutF1["\n\"%g\" is NOT a valid name.", [rope[nameRope]]]; RETURN; }; d.out.PutF["%g(\"%g\" is an invalid name) ... ", [rope[leader]], [rope[nameRope]]]; }; proc[name, nameRope, distingName, distingNameRope, ~problems]; ENDLOOP; }; DoUpdateCommand: PROC [d: MyData, cb: MaintainDefs.CmdButton, name, args: ROPE] = { UpdatePassword: PROC = { SELECT cb.cmd FROM set => { type: ROPE ¬ IF cb.what = password THEN "strong" ELSE "simple"; idName, dIdName, dParmName: Name; sameName: BOOL; dIdNameRope, dParmNameRope: ROPE; idName ¬ XNSAuth.GetIdentityDetails[d.identity].name; [dIdName, problems, , ] ¬ DistinguishedName[idName, c]; dIdNameRope ¬ XNSCHName.RopeFromName[dIdName]; IF problems THEN { d.out.PutF1["\nSorry, unable to discern logged-in user: \"%g\"? Password not changed.", [rope[dIdNameRope]]]; RETURN; }; [dParmName, problems, , ] ¬ DistinguishedName[nsName, c]; dParmNameRope ¬ XNSCHName.RopeFromName[dParmName]; IF problems THEN { d.out.PutF1["\nSorry, unable to distinguish name: \"%g\". Password not changed.", [rope[dParmNameRope]]]; RETURN; }; sameName ¬ Rope.Equal[dIdNameRope, dParmNameRope, FALSE]; SELECT TRUE FROM sameName, d.level = normal, d.level = owner => { IF ~sameName THEN { d.out.PutF["\nSorry, in Normal and Owner level the provided name must be the same as the logged in user (\"%g\" # \"%g\"). Password not changed.", [rope[dParmNameRope]], [rope[dIdNameRope]]]; RETURN; }; d.out.PutF["\nChanging my (%g) password (%g) ...", [rope[type]], [rope[dIdNameRope]]]; [] ¬ XNSAuth.ChangeMyPasswords[d.identity, args, cb.what = password, cb.what = simple ! XNSAuth.AuthenticationError => { d.out.PutF1[" Error: %g.", [rope[ExposeAuthProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; XNSAuth.CallError => { d.out.PutF1[" Error: %g.", [rope[ExposeAuthCallProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; ]; }; ENDCASE => { d.out.PutF["\nChanging (%g) password for \"%g\" ...", [rope[type]], [rope[name]]]; d.out.PutF1[" deleting existing %g key ...", [rope[type]]]; IF cb.what = password THEN [] ¬ XNSAuth.DeleteStrongKey[d.identity, nsName ! XNSAuth.AuthenticationError => { d.out.PutF1[" %g ...", [rope[ExposeAuthProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; XNSAuth.CallError => { d.out.PutF1[" %g ...", [rope[ExposeAuthCallProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; ] ELSE [] ¬ XNSAuth.DeleteSimpleKey[d.identity, nsName ! XNSAuth.AuthenticationError => { d.out.PutF1[" %g ...", [rope[ExposeAuthProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; XNSAuth.CallError => { d.out.PutF1[" %g ...", [rope[ExposeAuthCallProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; ]; problems ¬ FALSE; d.out.PutF1[" creating new %g key ...", [rope[type]]]; IF cb.what = password THEN [] ¬ XNSAuth.CreateStrongKey[d.identity, nsName, XNSAuth.StrongKeyFromPassword[args] ! XNSAuth.AuthenticationError => { d.out.PutF1[" %g ...", [rope[ExposeAuthProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; XNSAuth.CallError => { d.out.PutF1[" %g ...", [rope[ExposeAuthCallProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; ] ELSE [] ¬ XNSAuth.CreateSimpleKey[d.identity, nsName, XNSAuth.SimpleKeyFromPassword[args] ! XNSAuth.AuthenticationError => { d.out.PutF1[" %g ...", [rope[ExposeAuthProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; XNSAuth.CallError => { d.out.PutF1[" %g ...", [rope[ExposeAuthCallProblem[problem]]]]; problems ¬ TRUE; CONTINUE }; ]; }; IF ~problems THEN d.out.PutRope[" ok."] ELSE d.out.PutRope[" errors."]; }; ENDCASE => NotImplementedYet[d]; }; UpdateAlias: PROC = { UpdateOneAlias: PROC [thisName: Name, thisNameRope: ROPE, distingName: Name, distingNameRope: ROPE, disting: BOOL] = { SELECT cb.cmd FROM add => { IF disting THEN d.out.PutF1["\nSorry, that alias/name (%g) is already taken.", [rope[thisNameRope]]] ELSE { d.out.PutF["\nAdding alias \"%g\" for \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; [] ¬ XNSCH.AddAlias[c, nsName, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; remove => { IF ~disting THEN d.out.PutF1["\nSorry, that alias (%g) is not currently assigned.", [rope[thisNameRope]]] ELSE { d.out.PutF1["\nRemoving alias \"%g\" ...", [rope[thisNameRope]]]; [] ¬ XNSCH.DeleteAlias[c, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE d.out.PutRope[" ok."]; }; DoForEachArgument[d, c, UpdateOneAlias, FALSE, TRUE]; }; RemoveProperty: PROC [prop: Property] = { d.out.PutF["\nRemoving %g property from \"%g\" ...", [rope[ExposePropertyCode[prop]]], [rope[name]]]; [] ¬ XNSCH.DeleteProperty[c, nsName, prop ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; UpdateRemark: PROC = { SELECT cb.what FROM individualRemark => { d.out.PutF["\nSetting remark for \"%g\" to \"%g\" ...", [rope[name]], [rope[args]]]; [] ¬ XNSCH.ChangeItemProperty[c, nsName, user, XNSCHItemOps.ItemFromRope[args].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; groupRemark => { d.out.PutF["\nSetting remark for \"%g\" to \"%g\" ...", [rope[name]], [rope[args]]]; [] ¬ XNSCH.ChangeItemProperty[c, nsName, userGroup, XNSCHItemOps.ItemFromRope[args].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE { d.out.PutRope[" ok."]; }; }; UpdateProperties: PROC = { atom: ATOM ¬ NARROW[d.cmdData]; SetRopeProperty: PROC [prop: Property, type, value: ROPE] = { d.out.PutF["\nSetting %g for \"%g\" to \"%g\" ...", [rope[type]], [rope[name]], [rope[value]]]; problems ¬ FALSE; [] ¬ XNSCH.AddItemProperty[c, nsName, prop, XNSCHItemOps.ItemFromRope[value].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { problems ¬ FALSE; [] ¬ XNSCH.ChangeItemProperty[c, nsName, prop, XNSCHItemOps.ItemFromRope[value].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; SetNamePropertyFromRope: PROC [prop: Property, type, value: ROPE] = { item: Item; thisName: Name; d.out.PutF["\nSetting %g for \"%g\" to \"%g\" ...", [rope[type]], [rope[name]], [rope[value]]]; thisName ¬ XNSCHName.NameFromRope[value ! XNSCHName.FieldTooLong => {RESUME}]; item ¬ XNSCHItemOps.ItemFromName[thisName].newItem; problems ¬ FALSE; [] ¬ XNSCH.AddItemProperty[c, nsName, prop, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { problems ¬ FALSE; [] ¬ XNSCH.ChangeItemProperty[c, nsName, prop, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; SetListOfCard16PropertyFromRope: PROC [prop: Property, type, value: ROPE] = { item: Item ¬ ItemFromListOfCard16Rope[value]; problems ¬ FALSE; IF item = NIL THEN { d.out.PutF1["\n\"%g\" is not a valid list of CARD16.", [rope[value]]]; RETURN; }; d.out.PutF["\nSetting %g for \"%g\" to \"%g\" ...", [rope[type]], [rope[name]], [rope[value]]]; [] ¬ XNSCH.AddItemProperty[c, nsName, prop, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { problems ¬ FALSE; [] ¬ XNSCH.ChangeItemProperty[c, nsName, prop, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; SELECT atom FROM $UserFileService => NotImplementedYet[d]; $AddressList => { addresses: LIST OF XNS.Address; addresses ¬ AddressListFromRopeList[args ! Convert.Error => {problems ¬ TRUE; CONTINUE}]; IF problems THEN { d.out.PutF1["\nSorry, but you have given an invalid address: \"%g\"", [rope[args]]]; GOTO someProblems; }; d.out.PutRope["\nSetting the Address List property to: "]; PutAddressList[d, addresses]; d.out.PutRope[" ..."]; problems ¬ FALSE; [] ¬ XNSCH.ChangeItemProperty[c, nsName, addressList, XNSCHItemOps.ItemFromAddressList[addresses].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { problems ¬ FALSE; [] ¬ XNSCH.AddItemProperty[c, nsName, addressList, XNSCHItemOps.ItemFromAddressList[addresses].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; d.out.PutF1[" %g.", [rope[IF ~problems THEN "ok" ELSE "errors"]]]; EXITS someProblems => NULL; }; $PrintService => SetRopeProperty[printService, "print service remark", args]; $FileSerivce => SetRopeProperty[fileService, "file service remark", args]; $CHService => SetRopeProperty[clearinghouseService, "clearingHouse service remark", args]; $UserRemark => SetRopeProperty[user, "user remark", args]; $GroupRemark => SetRopeProperty[userGroup, "group remark", args]; $AssociatedWorkstation => SetNamePropertyFromRope[associatedWorkstation, "Associated Workstation name", args]; $RopePropFromSelection => SetRopeProperty[PropertyFromSelection[d], ExposePropertyCode[PropertyFromSelection[d]], args]; $NamePropFromSelection => SetNamePropertyFromRope[PropertyFromSelection[d], ExposePropertyCode[PropertyFromSelection[d]], args]; $ListOfCard16PropFromSelection => SetListOfCard16PropertyFromRope[PropertyFromSelection[d], ExposePropertyCode[PropertyFromSelection[d]], args]; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE { d.out.PutRope[" ok."]; }; }; UpdateMember: PROC = { UpdateOneMember: PROC [thisName: Name, thisNameRope: ROPE, distingName: Name, distingNameRope: ROPE, disting: BOOL]= { myGroup: Name ¬ nsName; myGroupRope: ROPE ¬ name; changed: BOOL ¬ FALSE; IF d.level IN [normal..owner] THEN [myGroup, myGroupRope, changed] ¬ GetPossibleSubList[nsName]; SELECT cb.cmd FROM add => { IF disting THEN { d.out.PutF["\nAdding member \"%g\" to \"%g\" ...", [rope[distingNameRope]], [rope[name]]]; IF changed THEN d.out.PutF1[" split-list, using \"%g\" sub-list ...", [rope[myGroupRope]]]; [] ¬ XNSCH.AddMember[c, myGroup, prop, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; } ELSE { d.out.PutF["\nAdding (possibly not distinguished) member \"%g\" to \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; IF changed THEN d.out.PutF1[" split-list, using \"%g\" sub-list ...", [rope[myGroupRope]]]; [] ¬ XNSCH.AddMember[c, myGroup, prop, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; remove => { d.out.PutF["\nRemoving member \"%g\" from \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; IF changed THEN d.out.PutF1[" split-list, using \"%g\" sub-list ...", [rope[myGroupRope]]]; [] ¬ XNSCH.DeleteMember[c, myGroup, prop, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { [distingName, problems, , ] ¬ DistinguishedName[thisName, c]; IF ~problems THEN { distingNameRope ¬ XNSCHName.RopeFromName[distingName]; d.out.PutF1[" trying distinguished name \"%g\" ...", [rope[distingNameRope]]]; [] ¬ XNSCH.DeleteMember[c, myGroup, prop, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE d.out.PutRope[" ok."]; }; DoForEachArgument[d, c, UpdateOneMember, cb.cmd = add, cb.cmd = add]; }; UpdateOwner: PROC = { UpdateOneOwner: PROC [thisName: Name, thisNameRope: ROPE, distingName: Name, distingNameRope: ROPE, disting: BOOL]= { SELECT cb.cmd FROM add => { IF disting THEN { d.out.PutF["\nAdding owner (administrator) \"%g\" to \"%g\" ...", [rope[distingNameRope]], [rope[name]]]; [] ¬ XNSCHACL.AddMemberToPropertyACL[c, nsName, members, administrators, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; } ELSE { d.out.PutF["\nAdding (possibly not distinguished) owner (administrator) \"%g\" to \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; [] ¬ XNSCHACL.AddMemberToPropertyACL[c, nsName, members, administrators, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; remove => { d.out.PutF["\nRemoving owner (administrator) \"%g\" from \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; [] ¬ XNSCHACL.DeleteMemberFromPropertyACL[c, nsName, members, administrators, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { [distingName, problems, , ] ¬ DistinguishedName[thisName, c]; IF ~problems THEN { d.out.PutF1[" trying distinguished name \"%g\" ...", [rope[distingNameRope]]]; [] ¬ XNSCHACL.DeleteMemberFromPropertyACL[c, nsName, members, administrators, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE d.out.PutRope[" ok."]; }; DoForEachArgument[d, c, UpdateOneOwner, cb.cmd = add, cb.cmd = add]; }; UpdateFriend: PROC = { UpdateOneFriend: PROC [thisName: Name, thisNameRope: ROPE, distingName: Name, distingNameRope: ROPE, disting: BOOL]= { SELECT cb.cmd FROM add => { IF disting THEN { d.out.PutF["\nAdding friend (self-controller) \"%g\" to \"%g\" ...", [rope[distingNameRope]], [rope[name]]]; [] ¬ XNSCHACL.AddMemberToPropertyACL[c, nsName, members, selfControl, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; } ELSE { d.out.PutF["\nAdding (possibly not distinguished) friend (self-controller) \"%g\" to \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; [] ¬ XNSCHACL.AddMemberToPropertyACL[c, nsName, members, selfControl, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; remove => { d.out.PutF["\nRemoving friend (self-controller) \"%g\" from \"%g\" ...", [rope[thisNameRope]], [rope[name]]]; [] ¬ XNSCHACL.DeleteMemberFromPropertyACL[c, nsName, members, selfControl, thisName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { [distingName, problems, , ] ¬ DistinguishedName[thisName, c]; IF ~problems THEN { d.out.PutF1[" trying distinguished name \"%g\" ...", [rope[distingNameRope]]]; [] ¬ XNSCHACL.DeleteMemberFromPropertyACL[c, nsName, members, selfControl, distingName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE d.out.PutRope[" ok."]; }; <<-- we set check to FALSE because friends should be able to be things like "*:*:Xerox">> DoForEachArgument[d, c, UpdateOneFriend, FALSE, cb.cmd = add]; }; UpdateSelf: PROC = { myGroup: Name; myGroupRope: ROPE; changed: BOOL ¬ FALSE; [myGroup, myGroupRope, changed] ¬ GetPossibleSubList[nsName]; SELECT cb.cmd FROM add => { d.out.PutF1["\nAdding self to \"%g\" ...", [rope[name]]]; IF changed THEN d.out.PutF1[" split-list, using \"%g\" sub-list ...", [rope[myGroupRope]]]; [] ¬ XNSCH.AddSelf[c, myGroup, members ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; remove => { d.out.PutF1["\nRemoving self from \"%g\" ...", [rope[name]]]; IF changed THEN d.out.PutF1[" split-list, using \"%g\" sub-list ...", [rope[myGroupRope]]]; [] ¬ XNSCH.DeleteSelf[c, myGroup, members ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE { d.out.PutRope[" ok."]; }; }; UpdateOccurrences: PROC = { SELECT cb.cmd FROM add => NotImplementedYet[d]; remove => NotImplementedYet[d]; ENDCASE => NotImplementedYet[d]; }; UpdateMailbox: PROC = { properties: XNSCH.Properties ¬ GetProperties[nsName, c]; item: Item; mbl: LIST OF ROPE ¬ NIL; existingMailboxes: LIST OF ROPE ¬ NIL; IF HasProperty[mailboxes, properties] THEN existingMailboxes ¬ GetExistingMailboxes[nsName, c] ELSE { d.out.PutRope[" creating mailboxes property ..."]; [] ¬ XNSCH.AddItemProperty[c, nsName, mailboxes, MailboxItemFromList[NIL] ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; FOR l: LIST OF ROPE ¬ d.argList, l.rest WHILE l # NIL DO distingName: Name; problems: BOOL; [distingName, problems, , ] ¬ DistinguishedNameFromRope[l.first]; IF problems THEN distingName ¬ XNSCHName.NameFromRope[l.first]; mbl ¬ CONS[XNSCHName.RopeFromName[distingName], mbl]; ENDLOOP; SELECT cb.cmd FROM add => { existingMailboxes ¬ AddRopesToList[existingMailboxes, mbl]; }; remove => { existingMailboxes ¬ RemoveRopesFromList[existingMailboxes, d.argList]; existingMailboxes ¬ RemoveRopesFromList[existingMailboxes, mbl]; }; ENDCASE => { NotImplementedYet[d]; RETURN; }; IF existingMailboxes = NIL THEN { d.out.PutRope[" no more mailboxes, deleting mailboxes property ..."]; [] ¬ XNSCH.DeleteProperty[c, nsName, mailboxes ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; } ELSE { d.out.PutRope[" changing mailboxes property to: "]; PutRopeList[d, existingMailboxes]; d.out.PutRope[" ..."]; item ¬ MailboxItemFromList[existingMailboxes]; [] ¬ XNSCH.ChangeItemProperty[c, nsName, mailboxes, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; UpdateForwarding: PROC = { DoNothingEnumeratorProc: PROC [XNSCH.ElementStreamProc] = {RETURN}; GetProperties: PROC [name: Name] RETURNS [XNSCH.Properties] = { [, properties] ¬ XNSCH.GetProperties[c, name ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; RETURN[properties]; }; HasAtLeastOneMember: PROC [group: Name] RETURNS[BOOL] = { BumpCount: PROC [name: Name] = { count ¬ count + 1; }; count: CARD ¬ 0; [] ¬ XNSCH.ListMembers[c, group, members, BumpCount ! XNSCH.Error => {CONTINUE}]; RETURN[count > 0]; }; properties: XNSCH.Properties ¬ GetProperties[nsName]; d.out.PutF[" %g forwarding %g \"%g\"...", [rope[SELECT cb.cmd FROM add => "adding", remove => "removing", ENDCASE => "???"]], [rope[SELECT cb.cmd FROM add => "to", remove => "from", ENDCASE => "???"]], [rope[name]]]; IF ~HasProperty[user, properties] THEN { d.out.PutRope[" must be a user."]; RETURN; }; SELECT cb.cmd FROM add => { IF HasProperty[mailboxes, properties] THEN { d.out.PutRope[" This user presently has Mailboxes, they should be removed ..."]; }; IF HasProperty[userGroup, properties] THEN d.out.PutRope[" group property already exists ..."] ELSE { d.out.PutRope[" adding group property ..."]; [] ¬ XNSCH.AddItemProperty[c, nsName, userGroup, XNSCHItemOps.ItemFromRope[args].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; IF HasProperty[members, properties] THEN d.out.PutRope[" members property already exists ..."] ELSE { d.out.PutRope[" adding members property ..."]; [] ¬ XNSCH.AddGroupProperty[c, nsName, members, DoNothingEnumeratorProc ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; d.out.PutRope["\n(Note: use Add Member to actually add names to the \"forwarding\" list.)"]; }; remove => { IF ~HasProperty[members, properties] THEN d.out.PutRope[" no members property to remove ..."] ELSE { IF HasAtLeastOneMember[nsName] THEN { d.out.PutRope[" still forwarding to at least one member, remove members first ..."]; RETURN; } ELSE { d.out.PutRope[" removing members property ..."]; [] ¬ XNSCH.DeleteProperty[c, nsName, members ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; }; IF ~HasProperty[userGroup, properties] THEN d.out.PutRope[" no group property to remove ..."] ELSE { d.out.PutRope[" removing group property ..."]; [] ¬ XNSCH.DeleteProperty[c, nsName, userGroup ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; d.out.PutRope["\n(Note: use Remove Member to actually remove names from the \"forwarding\" list.)"]; }; ENDCASE => NotImplementedYet[d]; }; UpdateCreate: PROC = { CreateUserData: PROC [name: Name] = { fsName: Name ¬ [name.organization, name.domain, "UNKNOWN"]; item: Item ¬ XNSCHItemOps.ItemFromCard16[Rope.FindBackward[name.object, " "]+1].newItem; [] ¬ XNSCHItemOps.NameIntoItem[item, fsName, 1]; [] ¬ XNSCH.AddItemProperty[c, name, userData, item ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; SELECT cb.what FROM createIndividual => { atom: ATOM ¬ NARROW[d.cmdData]; SELECT atom FROM $CreateCHS => { address: XNS.Address; address ¬ Convert.XNSAddressFromRope[args ! Convert.Error => {problems ¬ TRUE; CONTINUE}]; IF problems THEN { d.out.PutF1["\nYou must provide a valid address; \"%g\" is invalid.", [rope[args]]]; GOTO someProblems; }; address.socket ¬ XNS.unknownSocket; nsName ¬ [object: nsName.object, domain: "CHServers", organization: "CHServers"]; name ¬ XNSCHName.RopeFromName[nsName]; d.out.PutF1["\nCreating CHS entry for \"%g\" ...", [rope[name]]]; [] ¬ XNSCH.Add[c, nsName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN GOTO someProblems; d.out.PutF1[" adding address = %g ...", [rope[Convert.RopeFromXNSAddress[address]]]]; [] ¬ XNSCH.AddItemProperty[c, nsName, addressList, XNSCHItemOps.ItemFromAddressList[LIST[address]].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN GOTO someProblems; d.out.PutRope[" adding mailboxes property ..."]; [] ¬ XNSCH.AddItemProperty[c, nsName, mailboxes, MailboxItemFromList[LIST[name]] ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN GOTO someProblems; d.out.PutRope[" adding clearinghouseService property ..."]; [] ¬ XNSCH.AddItemProperty[c, nsName, clearinghouseService, NEW[CHOpsP2V3.ItemObject[0]] ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; d.out.PutF1[" %g.", [rope[IF ~problems THEN "ok" ELSE "errors"]]]; EXITS someProblems => NULL; }; $CreateObject => { d.out.PutF1["\nCreating object \"%g\" ...", [rope[name]]]; [] ¬ XNSCH.Add[c, nsName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; ENDCASE => { d.out.PutF1["\nCreating individual \"%g\" ...", [rope[name]]]; [] ¬ XNSCH.Add[c, nsName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN [] ¬ XNSCH.AddItemProperty[c, nsName, user, XNSCHItemOps.ItemFromRope[args].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN CreateUserData[nsName]; }; }; createGroup => { DoNothingEnumeratorProc: PROC [XNSCH.ElementStreamProc] = {RETURN}; d.out.PutF1["\nCreating group \"%g\" ...", [rope[name]]]; [] ¬ XNSCH.Add[c, nsName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN [] ¬ XNSCH.AddItemProperty[c, nsName, userGroup, XNSCHItemOps.ItemFromRope[args].newItem ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN [] ¬ XNSCH.AddGroupProperty[c, nsName, members, DoNothingEnumeratorProc ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE { d.out.PutRope[" ok."]; }; }; UpdateDelete: PROC = { d.out.PutF1["\nDeleting object \"%g\" ...", [rope[name]]]; [] ¬ XNSCH.Delete[c, nsName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; problems ¬ FALSE; } ELSE { d.out.PutRope[" ok."]; }; }; c: XNSCH.Conversation ¬ XNSCH.InitiateConversation[d.identity, d.conversationAddress]; eC: XNSCH.ErrorCode; eW: XNSCH.Which; problems: BOOL ¬ FALSE; nsName, argAsName: Name; prop: Property; atom: ATOM; IF ISTYPE[d.cmdData, ATOM] THEN { atom ¬ NARROW[d.cmdData]; prop ¬ PropertyFromAtom[atom, d]; }; nsName ¬ XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => {RESUME;}]; argAsName ¬ XNSCHName.NameFromRope[args ! XNSCHName.FieldTooLong => {RESUME;}]; IF cb.what # createIndividual AND cb.what # createGroup AND ~CheckName[nsName, c] THEN { d.out.PutF1["\"%g\" is an invalid name.", [rope[XNSCHName.RopeFromName[nsName]]]]; XNSCH.TerminateConversation[c]; RETURN; }; SELECT cb.what FROM password, simple => UpdatePassword[]; alias => { IF cb.cmd = remove THEN { IF atom = $RemoveAlias THEN UpdateAlias[] ELSE RemoveProperty[PropertyFromSelection[d]]; } ELSE UpdateAlias[]; }; self => UpdateSelf[]; individualRemark, groupRemark => UpdateRemark[]; fileService => UpdateProperties[]; member => UpdateMember[]; owner => UpdateOwner[]; friend => UpdateFriend[]; mailbox => UpdateMailbox[]; forwarding => UpdateForwarding[]; occurrences => UpdateOccurrences[]; createIndividual, createGroup => UpdateCreate[]; delete => UpdateDelete[]; ENDCASE => NotImplementedYet[d]; XNSCH.TerminateConversation[c]; }; HasProperty: PROC [prop: Property, properties: XNSCH.Properties] RETURNS [BOOL] = { FOR pi: CARDINAL IN [0..properties.length) DO IF properties[pi] = prop THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; DoTypeCommand: PROC [d: MyData, cb: MaintainDefs.CmdButton, name, args: ROPE] = { PutOneFink: PROC [fink: Name, allDownList: LIST OF ROPE, c: XNSCH.Conversation, doDelete: BOOL ¬ FALSE, group: Name ¬ [NIL, NIL, NIL]] RETURNS [LIST OF ROPE] = { RopeInList: PROC [r: ROPE, l: LIST OF ROPE] RETURNS [BOOL] = { FOR l ¬ l, l.rest WHILE l # NIL DO IF Rope.Equal[r, l.first, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; deleteThisFink: BOOL ¬ FALSE; nr: ROPE = XNSCHName.RopeFromName[fink]; IF d.verbose THEN { problems: BOOL ¬ FALSE; eC: XNSCH.ErrorCode; eW: XNSCH.Which; properties: XNSCH.Properties; domainOrganization: ROPE ¬ Rope.Cat[fink.domain, ":", fink.organization]; IF RopeInList[domainOrganization, allDownList] THEN {eC ¬ allDown; problems ¬ TRUE} ELSE [, properties] ¬ XNSCH.GetProperties[c, fink ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; SELECT TRUE FROM problems => SELECT eC FROM illegalPropertyID, illegalOrganizationName, illegalDomainName, illegalObjectName, noSuchOrganization, noSuchDomain, noSuchObject => { IF ExternalMailName[fink, c] THEN { d.out.PutF1["\n \"%g\" => possible external mail name", [rope[nr]]]; } ELSE { d.out.PutF["\n \"%g\" => %g", [rope[nr]], [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; deleteThisFink ¬ TRUE; }; }; ENDCASE => { IF eC = allDown THEN IF ~RopeInList[domainOrganization, allDownList] THEN allDownList ¬ CONS[domainOrganization, allDownList]; d.out.PutF["\n \"%g\" => %g", [rope[nr]], [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; }; (~HasProperty[mailboxes, properties] AND ~HasProperty[members, properties]) => d.out.PutF1["\n \"%g\" => no mailbox or members.", [rope[nr]]]; ENDCASE; }; IF deleteThisFink AND doDelete THEN DO { problems ¬ FALSE; d.out.PutRope[" => Deleting ..."]; [] ¬ XNSCH.DeleteMember[c, group, members, fink ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF problems THEN { d.out.PutF1[" Error => %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; IF eC = overflowOfDataBase THEN { d.out.PutRope["; Pausing for 5 minutes and then I'll try again ..."]; FOR i: CARD IN [0..(5*60)) WHILE ~d.stop DO Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; IF d.stop THEN EXIT; LOOP; }; } ELSE d.out.PutRope[" deleted."]; EXIT; } ENDLOOP; count ¬ SUCC[count]; RETURN[allDownList]; }; PutOneName: PROC [name: Name] = { IF ~firstName OR (cb.what = matches AND ~d.firstTime) THEN d.out.PutRope[", "] ELSE {firstName ¬ FALSE; d.firstTime ¬ FALSE}; count ¬ SUCC[count]; d.out.PutF1["\"%g\"", [rope[XNSCHName.RopeFromName[name]]]]; }; PutOneDomainName: PROC [name: Name] = { IF firstName THEN firstName ¬ FALSE ELSE d.out.PutRope[", "]; count ¬ SUCC[count]; d.out.PutF["\"%g:%g\"", [rope[name.domain]], [rope[name.organization]]]; }; PutOneOrganizationName: PROC [name: Name] = { IF firstName THEN firstName ¬ FALSE ELSE d.out.PutRope[", "]; count ¬ SUCC[count]; d.out.PutF1["\"%g\"", [rope[name.organization]]]; }; PutItemAsRope: PROC [item: Item] = { rope: ROPE ¬ XNSCH.RopeFromItem[item]; d.out.PutF1["\"%g\"", [rope[rope]]]; }; PutItemAsName: PROC [item: Item, offset: INT ¬ 0] = { name: Name ¬ XNSCHItemOps.NameFromItem[item, offset].name; rope: ROPE ¬ XNSCHName.RopeFromName[name]; d.out.PutF1["\"%g\"", [rope[rope]]]; }; PutItemAsItem: PROC [item: Item, full: BOOL ¬ FALSE] = { d.out.PutF1["length = %g", [cardinal[item.length]]]; IF ~full OR item.length = 0 THEN RETURN; d.out.PutRope[": "]; FOR i: CARDINAL IN [0..item.length) DO IF i # 0 THEN d.out.PutRope[", "]; d.out.PutF["%g (%g)", [cardinal[item[i]]], [rope[Convert.RopeFromCard[item[i], 8]]]]; ENDLOOP; }; MaybePutItemAsRope: PROC [item: Item, full: BOOL ¬ FALSE] = { IF item # NIL AND item.length > 0 AND item.length = LOOPHOLE[1 + (item[0]+1)/2, CARDINAL] THEN PutItemAsRope[item] ELSE PutItemAsItem[item, full]; }; PutUserDataInfo: PROC [item: Item, user: ROPE, details: BOOL, leadingSpace: ROPE ¬ ""] = { name: Name; IF details THEN d.out.PutF["\n%gLast Name: \"%g\"", [rope[leadingSpace]], [rope[IF item.length <= 0 OR item[0] > Rope.Length[user] THEN "(Invalid Index)" ELSE Rope.Substr[user, item[0]]]]]; name ¬ XNSCHItemOps.NameFromItem[item, 1].name; d.out.PutF["\n%gUsers's File Service: \"%g\"", [rope[leadingSpace]], [rope[XNSCHName.RopeFromName[name]]]]; }; PutMailboxInfo: PROC [item: Item, leadingSpace: ROPE ¬ "", printTime: BOOL] = { ENABLE XNSCHItemOps.Error => { d.out.PutRope["\nMailboxes: malformed property!"]; GOTO OutOfHere; }; pos: INT ¬ 3; mailboxList: LIST OF Name; IF printTime THEN d.out.PutF["\n%gTime: %g", [rope[leadingSpace]], [rope[Convert.RopeFromTime[BasicTime.FromNSTime[NSTimeFromItem[item]]]]]]; d.out.PutF1["\n%gMailboxes: ", [rope[leadingSpace]]]; mailboxList ¬ XNSCHItemOps.NameListFromItem[item, 2].names; WHILE mailboxList # NIL DO d.out.PutF1["\"%g\"", [rope[XNSCHName.RopeFromName[mailboxList.first]]]]; IF mailboxList.rest # NIL THEN d.out.PutRope[", "]; mailboxList ¬ mailboxList.rest; ENDLOOP; EXITS OutOfHere => RETURN; }; PutItemAsAddressList: PROC [item: Item] = { addresses: LIST OF XNS.Address; addresses ¬ XNSCHItemOps.AddressListFromItem[item ! XNSCHItemOps.Error => {addresses ¬ NIL; CONTINUE}].addresses; PutAddressList[d, addresses]; }; PutItemAsAuthenticationLevel: PROC [item: Item] = { ENABLE XNSCHItemOps.Error => { d.out.PutRope["I don't understand: "]; PutItemAsItem[item, d.verbose]; GOTO OutOfHere; }; simpleSupported: BOOL = XNSCHItemOps.BoolFromItem[item, 0].bool; strongSupported: BOOL = XNSCHItemOps.BoolFromItem[item, 1].bool; IF simpleSupported THEN d.out.PutRope["simpleSupported"]; IF strongSupported THEN d.out.PutF1["%gstrongSupported", [rope[IF simpleSupported THEN ", " ELSE ""]]]; EXITS OutOfHere => RETURN; }; CountMembers: PROC [group: Name, prop: Property] RETURNS[CARD] = { BumpCount: PROC [name: Name] = { count ¬ count + 1; }; count: CARD ¬ 0; [] ¬ XNSCH.ListMembers[c, group, prop, BumpCount ! XNSCH.Error => {CONTINUE}]; RETURN[count]; }; GiveNSInfo: PROC [level: What] = { OPEN CHEntriesP0V0; giveDetails: BOOL ¬ FALSE; properties: XNSCH.Properties ¬ NIL; [distingName , properties] ¬ XNSCH.GetProperties[c, pattern ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF d.stop THEN RETURN; IF problems THEN SELECT eC FROM noSuchObject, allDown, wasUpNowDown => RETURN; ENDCASE => IF ExternalMailName[pattern, c] THEN NULL ELSE RETURN; IF d.firstTime THEN d.firstTime ¬ FALSE ELSE d.out.PutChar['\n]; IF problems THEN { d.out.PutF1["\nName: \"%g\"", [rope[name]]]; d.out.PutF["\nThe domain \"%g:%g\" appears to be connected via an External Mail Gateway. (An External Mail Gateway is a \"controlled\" gateway that passes mail only -- it does not allow access to file servers, clearinghouses, etc.) The name \"%g\" may or may not be valid in that domain -- it is impossible to determine that from here. Individuals within such a domain are most likely not Xerox employes. Caution should be exercised when sending sensitive data to this name or before adding such a name to a DL.", [rope[pattern.domain]], [rope[pattern.organization]], [rope[pattern.object]]]; problems ¬ FALSE; RETURN; }; d.out.PutF1["\nDistinguished name: \"%g\"", [rope[XNSCHName.RopeFromName[distingName]]]]; IF d.stop OR NARROW[d.cmdData, ATOM] = $DistingOnly THEN RETURN; d.out.PutRope["\nAliases: "]; [] ¬ XNSCH.ListAliases[c, pattern, PutOneName ! XNSCH.Error => {eC ¬ code; eW ¬ which; CONTINUE}]; IF count = 0 THEN d.out.PutRope["(none)"]; IF d.stop THEN RETURN; giveDetails ¬ cb.what = details; FOR pi: CARDINAL IN [0..properties.length) DO clProc: MaintainProcs.ChangeLooksProc ¬ LOOPHOLE[MaintainDefs.RetrieveProc[d.flavor, $ChangeLooks]]; unknown: BOOL; propInfo: PropertyInfoObject; propType: PropType; prop: Property ¬ properties.body[pi]; IF d.stop THEN RETURN; propInfo ¬ GetPropertyInfo[prop]; unknown ¬ propInfo.codeLabel = NIL; IF (unknown AND ~giveDetails) OR propInfo.detailed AND ~giveDetails THEN LOOP; IF ~propInfo.subLabels THEN d.out.PutF1["\n%g: ", [rope[IF unknown THEN Rope.Concat["Property ", propInfo.label] ELSE propInfo.label]]]; propType ¬ propInfo.propType; SELECT propType FROM group => { atom: ATOM = NARROW[d.cmdData, ATOM]; firstName ¬ TRUE; IF d.verbose THEN [] ¬ XNSCH.ListMembers[c, pattern, prop, PutOneName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}] ELSE d.out.PutF1["%g", [cardinal[CountMembers[pattern, prop]]]]; IF atom # $NoACLInfo THEN { FOR acl: AccessList IN [readAccess..selfControl] DO n: CARD ¬ count; IF d.stop THEN RETURN; IF clProc # NIL THEN clProc[d, 'i]; SELECT acl FROM readAccess => {d.out.PutRope["\nReaders: "];}; administrators => {d.out.PutRope["\nAdministrators: "];}; selfControl => {d.out.PutRope["\nSelfControllers: "];}; ENDCASE => LOOP; IF clProc # NIL THEN clProc[d, ' ]; firstName ¬ TRUE; [] ¬ XNSCHACL.ListMembersOfPropertyACL[c, pattern, prop, acl, PutOneName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF n = count THEN d.out.PutRope["(none)"]; ENDLOOP; }; }; ENDCASE => { item: Item; [, item] ¬ XNSCH.LookupItemProperty[c, pattern, prop ! XNSCH.Error => {CONTINUE}]; IF item # NIL THEN SELECT propType FROM unknown => MaybePutItemAsRope[item, d.verbose]; rope => PutItemAsRope[item]; name => PutItemAsName[item]; authenticationLevel => PutItemAsAuthenticationLevel[item]; addressList => PutItemAsAddressList[item]; userData => PutUserDataInfo[item, distingName.object, giveDetails, ""]; mailboxInfo => PutMailboxInfo[item, "", giveDetails]; ENDCASE => d.out.PutRope["???"]; }; ENDLOOP; }; c: XNSCH.Conversation ¬ XNSCH.InitiateConversation[d.identity, d.conversationAddress]; pattern: Name ¬ XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => {RESUME;}]; distingName: Name; fullName: ROPE; problems: BOOL ¬ FALSE; firstName: BOOL ¬ TRUE; count: CARD ¬ 0; eC: XNSCH.ErrorCode; eW: XNSCH.Which; fullName ¬ XNSCHName.RopeFromName[pattern]; SELECT cb.what FROM members => { prop: Property; atom: ATOM ¬ NARROW[d.cmdData]; prop ¬ PropertyFromAtom[atom, d]; IF ~d.firstTime THEN d.out.PutChar['\n]; d.out.PutF1["\nMembers of \"%g\":\n", [rope[fullName]]]; [] ¬ XNSCH.ListMembers[c, pattern, prop, PutOneName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN d.out.PutF["\n(%g %g)", [cardinal[count]], [rope[MaintainMisc.Plural["member", "members", count]]]]; }; finks => { start, finish: BasicTime.GMT; startThisFink, finishThisFink: BasicTime.Pulses; membersList: LIST OF Name; allDownList: LIST OF ROPE; AddNameToList: PROC [name: Name] = { membersList ¬ CONS[name, membersList]; count ¬ count + 1; }; ReverseList: PROC [original: LIST OF Name] RETURNS[newList: LIST OF Name]= { FOR list: LIST OF Name ¬ original, list.rest UNTIL list = NIL DO newList ¬ CONS[list.first, newList]; ENDLOOP; }; IF d.firstTime THEN d.firstTime ¬ FALSE ELSE d.out.PutChar['\n]; d.out.PutF1["\nFinks in group \"%g\":", [rope[fullName]]]; start ¬ BasicTime.Now[]; IF d.debugSwitch THEN d.out.PutF1[" [%g]", [time[BasicTime.Now[]]]]; [] ¬ XNSCH.ListMembers[c, pattern, members, AddNameToList ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; d.out.PutF[" (%g %g)", [cardinal[count]], [rope[MaintainMisc.Plural["member", "members", count]]]]; IF ~problems THEN { membersList ¬ ReverseList[membersList]; FOR m: LIST OF Name ¬ membersList, m.rest WHILE m # NIL AND ~d.stop DO IF d.debugSwitch THEN d.out.PutF["\n ... \"%g\" [%g] ...", [rope[XNSCHName.RopeFromName[m.first]]], [time[BasicTime.Now[]]]]; startThisFink ¬ BasicTime.GetClockPulses[]; allDownList¬ PutOneFink[m.first, allDownList, c, d.autoDelete, pattern]; finishThisFink ¬ BasicTime.GetClockPulses[]; IF d.debugSwitch THEN d.out.PutF1[" (took: %g)", [rope[RealSecsToRope[BasicTime.PulsesToSeconds[finishThisFink-startThisFink]]]]]; ENDLOOP; finish ¬ BasicTime.Now[]; IF d.debugSwitch THEN d.out.PutF1["\n (Total: %g)", [rope[PeriodToRope[BasicTime.Period[start, finish]]]]]; }; }; matches => PutOneName[pattern]; summary => GiveNSInfo[summary]; details => GiveNSInfo[details]; domains => { orgNotProvided: ROPE = "orgNotProvided"; pattern ¬ XNSCHName.NameFromRope[name, orgNotProvided ! XNSCHName.FieldTooLong => {RESUME;}]; IF ~Rope.Equal[pattern.domain, orgNotProvided] THEN pattern.organization ¬ pattern.domain; pattern.domain ¬ pattern.object; pattern.object ¬ NIL; d.out.PutF1["\nDomains matching \"%g\": ", [rope[name]]]; XNSCH.EnumerateDomains[c, pattern, PutOneDomainName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN d.out.PutF["\n(%g %g)", [cardinal[count]], [rope[MaintainMisc.Plural["match", "matches", count]]]]; }; organizations => { pattern.organization ¬ pattern.object; pattern.domain ¬ NIL; pattern.object ¬ NIL; XNSCH.EnumerateOrganizations[c, pattern, PutOneOrganizationName ! XNSCH.Error => {eC ¬ code; eW ¬ which; problems ¬ TRUE; CONTINUE}]; IF ~problems THEN d.out.PutF["\n(%g %g)", [cardinal[count]], [rope[MaintainMisc.Plural["match", "matches", count]]]]; }; domainsServed => { n: CARD ¬ 0; ce: GluePruneHacks.CacheEntry; d.out.PutF1["\n\nDomains served by \"%g\": ", [rope[name]]]; ce ¬ GluePruneHacks.DomainsForServer[name]; d.out.PutF1["\nKey: \"%g\"", [rope[ce.key]]]; d.out.PutF1[", ok: %g", [rope[IF ce.ok THEN "TRUE" ELSE "FALSE"]]]; IF ~ce.ok THEN d.out.PutF1[", reason = %g", [rope[GluePruneHacks.ExposeErrorCode[ce.reason]]]]; d.out.PutRope["\nValue: "]; FOR rl: GluePruneHacks.RopeList ¬ ce.value, rl.rest WHILE rl # NIL DO d.out.PutF["%g\"%g\"", [rope[IF n = 0 THEN "" ELSE ", "]], [rope[rl.first]]]; n ¬ n + 1; ENDLOOP; d.out.PutF1["\nTotal Domains served: %g", [cardinal[n]]]; }; direct, occurrences => { FOR argList: LIST OF ROPE ¬ d.argList, argList.rest WHILE argList # NIL DO memberRopeToCheck: ROPE ¬ argList.first; memberToCheck: Name; yes: BOOL ¬ FALSE; <> memberToCheck ¬ XNSCHName.NameFromRope[memberRopeToCheck ! XNSCHName.FieldTooLong => {RESUME;}]; problems ¬ FALSE; [ , yes] ¬ XNSCH.IsMember[c, pattern, members, memberToCheck ! XNSCH.Error => {CONTINUE}]; IF ~problems THEN { IF cb.what = direct THEN d.out.PutF["\n\"%g\" IS%g a direct member of \"%g\".", [rope[memberRopeToCheck]], IF yes THEN [rope[""]] ELSE [rope[" NOT"]], [rope[XNSCHName.RopeFromName[pattern]]]] ELSE IF yes THEN { IF d.firstTime THEN d.firstTime ¬ FALSE ELSE d.out.PutRope[", "]; d.out.PutF1["\"%g\"", [rope[name]]]; }; }; ENDLOOP; }; extended => { FOR argList: LIST OF ROPE ¬ d.argList, argList.rest WHILE argList # NIL DO memberRopeToCheck: ROPE ¬ argList.first; memberToCheck: Name; yes: BOOL ¬ FALSE; <> memberToCheck ¬ XNSCHName.NameFromRope[memberRopeToCheck ! XNSCHName.FieldTooLong => {RESUME;}]; problems ¬ FALSE; [ , yes] ¬ XNSCH.IsMemberClosure[c, pattern, members, memberToCheck ! XNSCH.Error => {CONTINUE}]; IF ~problems THEN d.out.PutF["\n\"%g\" IS%g a member of \"%g\".", [rope[memberRopeToCheck]], IF yes THEN [rope[""]] ELSE [rope[" NOT"]], [rope[XNSCHName.RopeFromName[pattern]]]]; ENDLOOP; }; ENDCASE => NotImplementedYet[d]; IF problems THEN { d.out.PutF1["\nError: %g", [rope[ExposeErrorCode[eC, LOOPHOLE[eW]]]]]; }; XNSCH.TerminateConversation[c]; IF d.stop THEN { IO.PutRope[d.out, "\nStopping...\n"]}; }; NSTimeFromItem: PROC [item: Item, index: CARD ¬ 0] RETURNS [CARD] = { RETURN[ XNSCHItemOps.Card32FromItem[item, index ! XNSCHItemOps.Error => {GOTO OutOfHere}].card ]; EXITS OutOfHere => RETURN[BasicTime.ToNSTime[BasicTime.Now[]]]; }; GetProperties: PROC [name: Name, c: XNSCH.Conversation ¬ NIL] RETURNS [XNSCH.Properties] = { newConversation: BOOL ¬ c = NIL; properties: XNSCH.Properties; IF newConversation THEN c ¬ XNSCH.InitiateConversation[]; [, properties] ¬ XNSCH.GetProperties[c, name ! XNSCH.Error => {CONTINUE}]; IF newConversation THEN XNSCH.TerminateConversation[c]; RETURN[properties]; }; GetExistingMailboxes: PROC [name: Name, c: XNSCH.Conversation ¬ NIL] RETURNS [ropes: LIST OF ROPE] = { newConversation: BOOL ¬ c = NIL; lastRope: LIST OF ROPE; names: LIST OF Name; item: Item; IF newConversation THEN c ¬ XNSCH.InitiateConversation[]; [, item] ¬ XNSCH.LookupItemProperty[c, name, mailboxes ! XNSCH.Error => {CONTINUE}]; names ¬ XNSCHItemOps.NameListFromItem[item, 2 ! XNSCHItemOps.Error => { IF newConversation THEN XNSCH.TerminateConversation[c]; GOTO OutOfHere; }].names; WHILE names # NIL DO IF ropes = NIL THEN lastRope ¬ ropes ¬ LIST[XNSCHName.RopeFromName[name]] ELSE lastRope ¬ lastRope.rest ¬ LIST[XNSCHName.RopeFromName[name]]; names ¬ names.rest; ENDLOOP; IF newConversation THEN XNSCH.TerminateConversation[c]; EXITS OutOfHere => RETURN[NIL]; }; MailboxItemFromList: PROC [list: LIST OF ROPE, time: CARD ¬ BasicTime.ToNSTime[BasicTime.Now[]]] RETURNS [item: Item] = { names: CARD16 ¬ 0; thisName: Name; pos: CARD ¬ 3; FOR l: LIST OF ROPE ¬ list, l.rest WHILE l # NIL DO thisName ¬ XNSCHName.NameFromRope[l.first]; [item, pos] ¬ XNSCHItemOps.ItemFromName[thisName, pos, item]; names ¬ names + 1; ENDLOOP; [] ¬ XNSCHItemOps.Card32IntoItem[item, time, 0]; [] ¬ XNSCHItemOps.Card16IntoItem[item, names, 2]; }; ItemFromListOfCard16Rope: PROC [list: ROPE] RETURNS [item: Item] = { count: INT ¬ 0; number: CARD16; errors: BOOL ¬ FALSE; BumpCount: PROC [r: ROPE] = { number ¬ Convert.CardFromRope[r ! Convert.Error => {errors ¬ TRUE; CONTINUE}]; count ¬ count+1; }; FillInItem: PROC [r: ROPE] = { number ¬ Convert.CardFromRope[r]; item[count] ¬ number; count ¬ count+1; }; MaintainMisc.CallForItems[NEW[MyDataObject], list, BumpCount]; IF errors THEN RETURN[NIL]; item ¬ XNSCHItemOps.CreateNewItem[count]; count ¬ 0; MaintainMisc.CallForItems[NEW[MyDataObject], list, FillInItem]; RETURN[item]; }; AddressListFromRopeList: PROC [list: ROPE] RETURNS [addresses: LIST OF XNS.Address] = { lastAddress: LIST OF XNS.Address; AddAddress: PROC [r: ROPE] = { address: XNS.Address ¬ Convert.XNSAddressFromRope[r]; IF addresses = NIL THEN lastAddress ¬ addresses ¬ LIST[address] ELSE lastAddress ¬ lastAddress.rest ¬ LIST[address]; }; MaintainMisc.CallForItems[NEW[MyDataObject], list, AddAddress]; }; AddRopesToList: PROC [a, b: LIST OF ROPE] RETURNS [LIST OF ROPE] = { new: LIST OF ROPE; FOR a ¬ a, a.rest WHILE a # NIL DO new ¬ CONS[a.first, new]; ENDLOOP; FOR b ¬ b, b.rest WHILE b # NIL DO new ¬ CONS[b.first, new]; ENDLOOP; RETURN[new]; }; RemoveRopesFromList: PROC [a, b: LIST OF ROPE] RETURNS [LIST OF ROPE] = { new: LIST OF ROPE; FOR a ¬ a, a.rest WHILE a # NIL DO IF ~RopeInList[a.first, b] THEN new ¬ CONS[a.first, new]; ENDLOOP; RETURN[new]; }; PutRopeList: PROC [d: MyData, l: LIST OF ROPE] = { first: BOOL ¬ TRUE; FOR l ¬ l, l.rest WHILE l # NIL DO IF first THEN first ¬ FALSE ELSE d.out.PutRope[", "]; d.out.PutF1["%g", [rope[l.first]]]; ENDLOOP; }; PutAddressList: PROC [d: MyData, addressList: LIST OF XNS.Address] = { first: BOOL ¬ TRUE; WHILE addressList # NIL DO d.out.PutF["%g%g", [rope[IF first THEN "" ELSE ", "]], [rope[Convert.RopeFromXNSAddress[addressList.first]]]]; first ¬ FALSE; addressList ¬ addressList.rest; ENDLOOP; }; RopeInList: PROC [r: ROPE, l: LIST OF ROPE] RETURNS [BOOL] = { FOR l ¬ l, l.rest WHILE l # NIL DO IF Rope.Equal[r, l.first, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; DoSetServer: PUBLIC PROC [d: MyData, name: ROPE] = { tryCHS: BOOL ¬ FALSE; adr: XNS.Address ¬ XNS.unknownAddress; IF name = NIL OR Rope.Length[name] <= 1 THEN { d.out.PutRope["\nSetting NS server to ALL servers ... ok.\n"]; d.conversationAddress ¬ XNS.unknownAddress; RETURN; }; d.out.PutF1["\nSetting NS server to: %g ... ", [rope[name]]]; adr ¬ Convert.XNSAddressFromRope[name ! Convert.Error => {tryCHS ¬ TRUE; CONTINUE}]; IF tryCHS THEN [, adr] ¬ XNSCH.LookupAddressFromRope[name]; d.out.PutF1[" (%g) ok.\n", [rope[Convert.RopeFromXNSAddress[adr]]]]; d.conversationAddress ¬ adr; }; DistinguishedNameFromRope: PROC [name: ROPE, c: XNSCH.Conversation ¬ NIL] RETURNS [distingName: Name, problems: BOOL, errorCode: XNSCH.ErrorCode, which: XNSCH.Which, tooLong: BOOL] = { [distingName, problems, errorCode, which] ¬ DistinguishedName[XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => {tooLong ¬ TRUE; RESUME;}], c]; RETURN; }; DistinguishedName: PROC [name: Name, c: XNSCH.Conversation ¬ NIL] RETURNS [distingName: Name ¬ [NIL, NIL, NIL], problems: BOOL ¬ FALSE, errorCode: XNSCH.ErrorCode ¬ unknown, which: XNSCH.Which ¬ first] = { newConversation: BOOL ¬ c = NIL; IF newConversation THEN c ¬ XNSCH.InitiateConversation[]; distingName ¬ XNSCH.Lookup[c, name ! XNSCH.Error => {errorCode ¬ code; which ¬ which; problems ¬ TRUE; CONTINUE}]; IF newConversation THEN XNSCH.TerminateConversation[c]; }; ExternalMailName: PROC [name: Name, c: XNSCH.Conversation ¬ NIL] RETURNS [BOOL] = { <> errorCode: XNSCH.ErrorCode; problems: BOOL ¬ FALSE; newConversation: BOOL ¬ c = NIL; dots: ROPE = "..."; obj: ROPE = Rope.Concat[name.domain, name.organization]; IF Rope.Length[obj] > 40 THEN RETURN[FALSE]; IF newConversation THEN c ¬ XNSCH.InitiateConversation[]; [] ¬ XNSCH.Lookup[c, [dots, dots, obj] ! XNSCH.Error => {errorCode ¬ code; problems ¬ TRUE; CONTINUE}]; IF newConversation THEN XNSCH.TerminateConversation[c]; RETURN[~(problems AND errorCode = noSuchObject)]; }; IsGVName: PROC [name: ROPE] RETURNS[BOOLEAN] = { RETURN[name # NIL AND (Rope.Find[name, "@"] < 0)]; }; IsNsName: PROC [name: ROPE] RETURNS [BOOL] = { RETURN[name # NIL]; }; GetPossibleSubList: PROC [dl: Name] RETURNS [name: Name, nameRope: ROPE, changed: BOOL] = { changed ¬ FALSE; <> <> <> <> <
> <> <<};>> <<};>> nameRope ¬ XNSCHName.RopeFromName[dl]; RETURN[dl, nameRope, changed]; }; NeedsQuotes: PROC [r: ROPE] RETURNS [BOOL] ~ { IF Rope.Length[r] = 0 OR (Rope.Find[r, "\""] < 0 AND Rope.Find[r, " "] >= 0) THEN RETURN [TRUE]; RETURN[FALSE]; }; QuoteIfNeeded: PROC [r: ROPE] RETURNS [ROPE] ~ { IF NeedsQuotes[r] THEN RETURN [Rope.Cat["\"", r, "\""]]; RETURN[r]; }; EndsWith: PROC [a, b: ROPE] RETURNS [BOOL] = { bLength: INT = Rope.Length[b]; aLength: INT = Rope.Length[a]; IF aLength < bLength THEN RETURN[FALSE]; RETURN[Rope.Equal[Rope.Substr[a, aLength - bLength, bLength], b, FALSE]]; }; CheckName: PROC [name: Name, c: XNSCH.Conversation ¬ NIL] RETURNS[BOOL] = { ok: BOOL ¬ TRUE; checkForeign: BOOL ¬ FALSE; newConversation: BOOL ¬ c = NIL; IF newConversation THEN c ¬ XNSCH.InitiateConversation[]; [] ¬ XNSCH.Lookup[c, name ! XNSCH.Error => { SELECT code FROM illegalOrganizationName, illegalDomainName, illegalObjectName, noSuchObject => ok ¬ FALSE; noSuchOrganization, noSuchDomain => checkForeign ¬ TRUE; ENDCASE; CONTINUE}]; IF checkForeign THEN ok ¬ ExternalMailName[name, c]; IF newConversation THEN XNSCH.TerminateConversation[c]; RETURN[ok]; }; CheckNameRope: PROC [name: ROPE, c: XNSCH.Conversation ¬ NIL] RETURNS[BOOL] = { RETURN[CheckName[XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => {RESUME;}], c]]; }; PropertyInfoList: TYPE = LIST OF PropertyInfoObject; PropertyInfoObject: TYPE = RECORD [ prop: Property, label: ROPE, shortLabel: ROPE, codeLabel: ROPE, propType: PropType ¬ unknown, subLabels: BOOL ¬ FALSE, detailed: BOOL ¬ FALSE ]; all: Property = 0; alias: Property = 1; aliases: Property = 2; simpleKey: Property = 7; server: Property = 10024; nullProperty: Property = 37777777777B; propertyInfoList: PropertyInfoList ¬ LIST[ [addressList, "Address List", "AddressList", "addressList", addressList], [adobeService, "Adobe Service", "Adobe", "adobeService"], [alias, "Alias", "Alias", "alias"], [aliases, "Aliases", "Aliases", "aliases"], [all, "Any Object", "Any", "all"], [associatedWorkstation, "Associated Workstation", "AWKS", "associatedWorkstation", name], [authenticationLevel, "Authentication Level", "AuthLevel", "authenticationLevel", authenticationLevel, FALSE, TRUE], [authenticationService, "Authentication Service", "Auth", "authenticationService"], [authKeys, "Auth Keys", "AuthKeys", "authKeys", unknown, FALSE, TRUE], [clearinghouseService, "Clearinghouse Service", "CHS", "clearinghouseService"], [communicationsInterfaceUnit, "Communications Interface Unit", "CIU", "communicationsInterfaceUnit"], [externalCommunicationsService, "External Communications Service", "ECS", "externalCommunicationsService"], [fetchService, "Fetch Service", "Fetch", "fetchService"], [fileService, "File Service", "FS", "fileService", rope], [foreignMailSystemName, "Foreign Mail System Name", "ForeignMailSystemName", "foreignMailSystemName", name], [gatewayService, "Gateway Service", "GWS", "gatewayService"], [interactiveTerminalService, "Interactive Terminal Service", "ITS", "interactiveTerminalService"], [internetworkRoutingService, "Internetwork Routing Service", "IRS", "interactiveTerminalService"], [librarianService, "Librarian Service", "Librarian", "librarianService"], [mailboxes, "Mailboxes", "MBX", "mailboxes", mailboxInfo, TRUE], [mailGateway, "Mail Gateway", "MGW", "mailGateway", rope], [mailGatewayRouteData, "Mail Gateway Route Data", "MailGatewayRouteData", "mailGatewayRouteData", group], [mailService, "Mail Service", "MS", "mailService"], [members, "Members", "Members", "members", group], [network, "Network", "Net", "network"], [networkServers, "Network Servers", "NetworkServers", "networkServers"], [nullProperty, "Null Property", "NullProperty", "nullProperty"], [printService, "Print Service", "PS", "printService"], [remoteBatchService, "Remote Batch Service", "RBS", "remoteBatchService"], [rs232CData, "RS232CData", "RS232CData", "rs232CData"], [rs232CPort, "RS232CPort", "RS232CPort", "rs232CPort"], [server, "Server", "Server", "server"], [services, "Services", "Services", "services"], [simpleKey, "Simple Key", "SimpleKey", "simpleKey", unknown, FALSE, TRUE], [user, "User Remark", "User", "user", rope], [userData, "User Data", "UserData", "userData", userData, TRUE], [userGroup, "Group Remark", "Group", "userGroup", rope], [userPassword, "User Password", "Password", "userPassword", rope, FALSE, TRUE], [workstation, "Workstation", "Workstation", "workstation"] ]; HostAddressFromRope: PROC [r: ROPE] RETURNS[XNS.Host] = { RETURN[Convert.XNSHostFromRope[r ! Convert.Error => CONTINUE]]; RETURN[Convert.XNSAddressFromRope[r ! Convert.Error => CONTINUE].host]; RETURN[XNS.unknownHost]; }; HostAddressFromSelection: PROC [d: MyData] RETURNS[XNS.Host] = { sel: ROPE ¬ NARROW[d.moreData]; RETURN[HostAddressFromRope[sel]]; }; MatchHostAddressForObject: PROC [host: XNS.Host, obj: Name] RETURNS[BOOL] = { item: Item; addresses: LIST OF XNS.Address; error: BOOL ¬ FALSE; c: XNSCH.Conversation ¬ XNSCH.InitiateConversation[]; [, item] ¬ XNSCH.LookupItemProperty[c, obj, addressList ! XNSCH.Error => {error ¬ TRUE; CONTINUE}]; XNSCH.TerminateConversation[c]; IF error THEN RETURN[FALSE]; IF item.length > 0 THEN addresses ¬ XNSCHItemOps.AddressListFromItem[item ! XNSCHItemOps.Error => {error ¬ TRUE; CONTINUE}].addresses; IF error THEN RETURN[FALSE]; FOR addresses ¬ addresses, addresses.rest WHILE addresses # NIL DO IF host = addresses.first.host THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; PropertyFromRope: PROC [r: ROPE] RETURNS[Property] = { prop: Property; isNumber: BOOL ¬ TRUE; prop ¬ Convert.CardFromRope[r ! Convert.Error => {isNumber ¬ FALSE; CONTINUE}]; IF isNumber THEN RETURN[prop]; IF HostAddressFromRope[r] # XNS.unknownHost THEN RETURN[addressList]; FOR pi: PropertyInfoList ¬ propertyInfoList, pi.rest WHILE pi # NIL DO IF Rope.Equal[pi.first.label, r, FALSE] OR Rope.Equal[pi.first.shortLabel, r, FALSE] OR Rope.Equal[pi.first.codeLabel, r, FALSE] THEN RETURN[pi.first.prop]; ENDLOOP; r ¬ ReplaceThisRope[r, " ", ""]; r ¬ Rope.Substr[r, 0, Rope.Index[r, 0, "serv", FALSE]]; FOR pi: PropertyInfoList ¬ propertyInfoList, pi.rest WHILE pi # NIL DO IF Rope.Find[pi.first.label, r, 0, FALSE] # -1 OR Rope.Find[pi.first.codeLabel, r, 0, FALSE] # -1 THEN RETURN[pi.first.prop]; ENDLOOP; RETURN[nullProperty]; }; PropertyFromSelection: PROC [d: MyData] RETURNS[Property] = { sel: ROPE ¬ NARROW[d.moreData]; RETURN[PropertyFromRope[sel]]; }; PropertyFromAtom: PROC [atom: ATOM, d: MyData] RETURNS[Property] = { IF atom = $FromSelection THEN RETURN[PropertyFromSelection[d]]; RETURN[PropertyFromRope[Atom.GetPName[atom]]]; }; GetPropertyInfo: PROC [prop: Property] RETURNS [PropertyInfoObject] = { FOR pi: PropertyInfoList ¬ propertyInfoList, pi.rest WHILE pi # NIL DO IF prop = pi.first.prop THEN RETURN[pi.first]; ENDLOOP; RETURN[[prop, Convert.RopeFromCard[prop], Convert.RopeFromCard[prop], NIL, unknown, FALSE, FALSE]]; }; ExposePropertyCode: PROC [prop: Property] RETURNS [ROPE] = { pi: PropertyInfoObject ¬ GetPropertyInfo[prop]; IF pi.codeLabel # NIL THEN RETURN[pi.codeLabel] ELSE RETURN[Rope.Concat["property", pi.shortLabel]]; }; ExposeAuthCallProblem: PROC [problem: AuthenticationP14V2.CallProblem] RETURNS[ROPE] = { RETURN[SELECT problem FROM tooBusy => "tooBusy", accessRightsInsufficient => "accessRightsInsufficient", keysUnavailable => "keysUnavailable", strongKeyDoesNotExist => "strongKeyDoesNotExist", simpleKeyDoesNotExist => "simpleKeyDoesNotExist", strongKeyAlreadyRegistered => "strongKeyAlreadyRegistered", simpleKeyAlreadyRegistered => "simpleKeyAlreadyRegistered", domainForNewKeyUnavailable => "domainForNewKeyUnavailable", domainForNewKeyUnknown => "domainForNewKeyUnknown", badKey => "badKey", badName => "badName", databaseFull => "databaseFull", other => "other", ENDCASE => "UNKNOWN" ]; }; ExposeAuthProblem: PROC [problem: AuthenticationP14V2.Problem] RETURNS[ROPE] = { RETURN[SELECT problem FROM credentialsInvalid => "credentialsInvalid", verifierInvalid => "verifierInvalid", verifierExpired => "verifierExpired", verifierReused => "verifierReused", credentialsExpired => "credentialsExpired", inappropriateCredentials => "inappropriateCredentials", ENDCASE => "UNKNOWN" ]; }; ExposeErrorCode: PROC [arg: XNSCH.ErrorCode, level: NAT] RETURNS [res: ROPE] ~ { SELECT arg FROM notAllowed => res ¬ "notAllowed"; allDown => res ¬ "allDown"; wasUpNowDown => res ¬ "wasUpNowDown"; protocolError => res ¬ "protocolError"; cantConnectToServer => res ¬ "cantConnectToServer"; communicationFailure => res ¬ "communicationFailure"; serverTooBusy => res ¬ "serverTooBusy"; serviceNotExported => res ¬ "serviceNotExported"; illegalPropertyID => res ¬ "illegalPropertyID"; illegalOrganizationName => res ¬ "illegalOrganizationName"; illegalDomainName => res ¬ "illegalDomainName"; illegalObjectName => res ¬ "illegalObjectName"; noSuchOrganization => res ¬ "noSuchOrganization"; noSuchDomain => res ¬ "noSuchDomain"; noSuchObject => res ¬ "noSuchObject"; propertyIDNotFound => res ¬ "propertyIDNotFound"; wrongPropertyType => res ¬ "wrongPropertyType"; noChange => res ¬ "noChange"; outOfDate => res ¬ "outOfDate"; overflowOfName => res ¬ "overflowOfName"; overflowOfDataBase => res ¬ "overflowOfDataBase"; credentialsInvalid => res ¬ "credentialsInvalid"; credentialsTooWeak => res ¬ "credentialsTooWeak"; inappropriateConversation => res ¬ "inappropriateConversation"; unknown => res ¬ "unknown"; ENDCASE => ERROR }; ExposeWhich: PROC [arg: XNSCH.Which, level: NAT] RETURNS [res: ROPE] ~ { SELECT arg FROM first => res ¬ "first"; second => res ¬ "second"; ENDCASE => ERROR }; ReplaceThisRope: PROC [r, d, n: ROPE, all: BOOL ¬ TRUE, case: BOOL ¬ TRUE, pos: INT ¬ 0] RETURNS [ROPE] = { ld: INT ¬ Rope.Length[d]; ln: INT ¬ Rope.Length[n]; DO l: INT ¬ Rope.Length[r]; fi: INT ¬ Rope.Find[r, d, pos, case]; IF fi = -1 THEN EXIT; r ¬ Rope.Replace[r, fi, ld, n]; pos ¬ fi + ln; IF ~all THEN EXIT; ENDLOOP; RETURN[r]; }; NotImplementedYet: PROC [d: MyData] = { d.out.PutRope["\nSorry, that function not implemented yet..."]; }; RealSecsToRope: PROC [seconds: REAL] RETURNS [r: ROPE] = { intSeconds: INT ¬ Real.Fix[seconds]; mSecs: INT ¬ Real.Fix[(seconds - REAL[intSeconds]) * 1000]; r ¬ PeriodToRope[intSeconds]; r ¬ Rope.Cat[ r, ", ", Convert.RopeFromInt[mSecs], MaintainMisc.Plural[" mSec", " mSecs", mSecs]]; }; PeriodToRope: PROC [period: INT] RETURNS [r: ROPE] = { up: BasicTime.UnpackedPeriod ¬ BasicTime.UnpackPeriod[period]; IF up.hours > 0 THEN r ¬ Rope.Concat[ Convert.RopeFromInt[up.hours], MaintainMisc.Plural[" hour,", " hours,", up.hours]]; IF up.hours > 0 OR up.minutes > 0 THEN r ¬ Rope.Cat[ r, " ", Convert.RopeFromInt[up.minutes], MaintainMisc.Plural[" minute,", " minutes,", up.minutes]]; r ¬ Rope.Cat[ r, " ", Convert.RopeFromInt[up.seconds], MaintainMisc.Plural[" second", " seconds", up.seconds]]; }; }.