*** db.h        Sun Mar  2 23:18:26 1997
--- db.h        Sun Oct 26 07:08:08 1997
***************
*** 336,342 ****
     VF_READ = 01,
     VF_WRITE = 02,
     VF_EXEC = 04,
!     VF_DEBUG = 010
 } db_verb_flag;

 typedef enum {
--- 336,345 ----
     VF_READ = 01,
     VF_WRITE = 02,
     VF_EXEC = 04,
! /*** -o_Verbs Patch ***/
!     VF_DEBUG = 010,
!     VF_NOT_O = 02000
! /*** end -o_Verbs Patch ***/
 } db_verb_flag;

 typedef enum {
*** db_verbs.c  Sun Sep  7 19:58:37 1997
--- db_verbs.c  Tue Jan 20 16:57:40 1998
***************
*** 192,198 ****
 #define DOBJSHIFT  4
 #define IOBJSHIFT  6
 #define OBJMASK    0x3
! #define PERMMASK   0xF

 void
 db_add_verb(Objid oid, const char *vnames, Objid owner, unsigned flags,
--- 192,200 ----
 #define DOBJSHIFT  4
 #define IOBJSHIFT  6
 #define OBJMASK    0x3
! /*** -o_Verbs Patch ***/
! #define PERMMASK   0x70F
! /*** end -o_Verbs Patch ***/

 void
 db_add_verb(Objid oid, const char *vnames, Objid owner, unsigned flags,
*** objects.c   Sun Jul  6 23:24:54 1997
--- objects.c   Sun Nov 23 11:27:01 1997
***************
*** 27,32 ****
--- 27,35 ----
 #include "storage.h"
 #include "structures.h"
 #include "utils.h"
+ /*** -o_Verbs Patch ***/
+ #include "verbs.h"
+ /*** end -o_Verbs Patch ***/

 static int
 controls(Objid who, Objid what)
***************
*** 329,334 ****
--- 333,342 ----
           if (oid == what)
               return make_error_pack(E_RECMOVE);

+ /*** -o_Verbs Patch ***/
+         if (check_verbs_before_chparent(&parent, what))
+                 return make_error_pack(E_INVARG);
+ /*** end -o_Verbs Patch ***/
       if (!db_change_parent(what, parent))
           return make_error_pack(E_INVARG);
       else
*** verbs.c     Sun Mar  2 23:19:37 1997
--- verbs.c     Sun Oct 26 07:40:02 1997
***************
*** 88,115 ****
     if (!valid(*owner))
       return E_INVARG;

!     for (*flags = 0, s = v.v.list[2].v.str; *s; s++) {
!       switch (*s) {
!       case 'r':
!       case 'R':
!           *flags |= VF_READ;
!           break;
!       case 'w':
!       case 'W':
!           *flags |= VF_WRITE;
!           break;
!       case 'x':
!       case 'X':
!           *flags |= VF_EXEC;
!           break;
!       case 'd':
!       case 'D':
!           *flags |= VF_DEBUG;
!           break;
!       default:
!           return E_INVARG;
       }
!     }

     *names = v.v.list[3].v.str;
     while (**names == ' ')
--- 88,120 ----
     if (!valid(*owner))
       return E_INVARG;

! /*** -o_Verbs Patch ***/
!       if (server_flag_option("use_blocked_notation")) {
!          for (*flags = 0, s = v.v.list[2].v.str; *s; s++) {
!                       switch (*s) {
!                               case 'r': case 'R': *flags |= VF_READ;  break;
!                               case 'w': case 'W': *flags |= VF_WRITE; break;
!                               case 'x': case 'X': *flags |= VF_EXEC; break;
!                               case 'd': case 'D': *flags |= VF_DEBUG; break;
!                               case 'b': case 'B': *flags |= VF_NOT_O; break;
!                               default:
!                                       return E_INVARG;
!                       }
!               }
!       } else {
!          for (*flags = 0, *flags |= VF_NOT_O, s = v.v.list[2].v.str; *s; s++) {
!                       switch (*s) {
!                               case 'r': case 'R': *flags |= VF_READ;  break;
!                               case 'w': case 'W': *flags |= VF_WRITE; break;
!                               case 'x': case 'X': *flags |= VF_EXEC; break;
!                               case 'd': case 'D': *flags |= VF_DEBUG; break;
!                               case 'o': case 'O': *flags &= ~VF_NOT_O; break;
!                               default:
!                                       return E_INVARG;
!                       }
!               }
       }
! /*** end -o_Verbs Patch ***/

     *names = v.v.list[3].v.str;
     while (**names == ' ')
***************
*** 170,175 ****
--- 175,371 ----
     return E_NONE;
 }

+ /*** -o_Verbs Patch ***/
+ static const char cmap[] =
+   "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+   "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+   "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
+   "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
+   "\100\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
+   "\160\161\162\163\164\165\166\167\170\171\172\133\134\135\136\137"
+   "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
+   "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
+   "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+   "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+   "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+   "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+   "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+   "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+   "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+   "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";
+
+ static int
+ single_names_share_namespace(const char * cfoo, const char *cfend, const char * cbar, const char *cbend) {
+       int foostar, barstar;
+       const unsigned char  *foo = (const unsigned char *) cfoo;
+    const unsigned char  *bar = (const unsigned char *) cbar;
+    const unsigned char *fend = (const unsigned char *) cfend;
+       const unsigned char *bend = (const unsigned char *) cbend;
+
+    while (foo[0] != '*' && bar[0] != '*') {
+               if (foo == fend && bar == bend)
+                       return 1;
+               else if (foo == fend || bar == bend)
+                       return 0;
+               else if (cmap[*foo] != cmap[*bar])
+                       return 0;
+
+               foo++;
+               bar++;
+    }
+
+    foostar = (foo[0] == '*');
+    barstar = (bar[0] == '*');
+
+    while (foostar && !barstar) {
+       while (foo != fend && bar != bend && bar[0] != '*') {
+                  if (foo[0] == '*') {
+                       foo++;
+                       continue;
+                  }
+                  if (cmap[foo[0]] != cmap[bar[0]])
+                       return 0;
+                  foo++;
+                  bar++;
+               }
+               if (bar == bend)
+                       return 1;
+               else if (bar[0] == '*')
+                       barstar = 1;
+               else
+                       return foo[-1] == '*';
+       }
+
+       while (!foostar && barstar) {
+       while (foo != fend && bar != bend && foo[0] != '*') {
+                  if (bar[0] == '*') {
+                       bar++;
+                       continue;
+                  }
+                  if (cmap[foo[0]] != cmap[bar[0]])
+                       return 0;
+                  foo++;
+                  bar++;
+               }
+               if (foo == fend)
+                       return 1;
+               else if (foo[0] == '*')
+                       barstar = 1;
+               else
+                       return bar[-1] == '*';
+       }
+
+       while (foo != fend && bar != bend) {
+          if (foo[0] == '*') {
+               foo++;
+               continue;
+          }
+          if (bar[0] == '*') {
+               bar++;
+               continue;
+          }
+          if (cmap[foo[0]] != cmap[bar[0]])
+               return 0;
+          foo++;
+          bar++;
+       }
+       return 1;
+ }
+
+ static int
+ verbnames_share_namespace(const char *foo, const char *bar) {
+       const char * bar_start = bar;
+       const char *fend, *bend;
+
+       while (foo[0] != '\0') {
+               if (foo[0] == ' ') {
+                       foo++;
+                       continue;
+               }
+               for(fend = foo; fend[0] != '\0' && fend[0] != ' '; fend++);
+               bar = bar_start;
+               while (bar[0] != '\0') {
+                       if (bar[0] == ' ') {
+                               bar++;
+                               continue;
+                       }
+                       for (bend = bar; bend[0] != '\0' && bend[0] != ' '; bend++);
+                       if (bend-bar && fend-foo && single_names_share_namespace(foo, fend, bar, bend))
+                               return 1;
+                       bar = bend;
+               }
+               foo = fend;
+       }
+       return 0;
+ }
+
+ struct o_verbs_pack {
+       Objid                           owner;
+       const char *    names;
+ };
+
+
+ static enum error
+ name_conflict_with_ancestor(const Objid oid, Objid owner, const char
+ *names) {
+       Objid victim;
+       db_verb_handle v;
+       int i;
+
+       victim = oid;
+       while (valid(victim)) {
+               for (i = 0; i < db_count_verbs(victim); i++) {
+                       v = db_find_indexed_verb(victim, i+1);
+                       if ((db_verb_flags(v) & VF_NOT_O)
+                                 && (db_verb_owner(v) != owner)
+                                 && verbnames_share_namespace(names, db_verb_names(v)))
+                               return 1;
+               }
+               victim = db_object_parent(victim);
+       }
+       return 0;
+ }
+
+ static int
+ name_conflict_with_descendants_recursive(void *data, Objid oid) {
+       db_verb_handle v;
+       int i;
+
+       for (i = 0; i < db_count_verbs(oid); i++) {
+               v = db_find_indexed_verb(oid, i+1);
+               if (!is_wizard(db_verb_owner(v))
+                         && db_verb_owner(v) != ((struct o_verbs_pack*)data)->owner
+                         && verbnames_share_namespace(((struct o_verbs_pack*)data)->names, db_verb_names(v)))
+                       return 1;
+       }
+       return db_for_all_children(oid, name_conflict_with_descendants_recursive, data);
+ }
+
+
+ static int
+ name_conflict_with_descendants(Objid oid, Objid owner, const char *names) {
+       struct o_verbs_pack data;
+       data.owner = owner;
+       data.names = names;
+       return db_for_all_children(oid, name_conflict_with_descendants_recursive, &data);
+ }
+
+ int
+ check_verbs_before_chparent(void * new_parent, Objid oid) {
+       int i;
+       db_verb_handle v;
+
+       for (i = 0; i < db_count_verbs(oid); i++) {
+               v = db_find_indexed_verb(oid, i+1);
+               if (!is_wizard(db_verb_owner(v))
+                        && name_conflict_with_ancestor(*((Objid *)new_parent), db_verb_owner(v), db_verb_names(v)))
+                       return 1;
+       }
+       return db_for_all_children(oid, check_verbs_before_chparent, new_parent);
+ }
+
+ /*** end -o_Verbs Patch ***/
+
 static package
 bf_add_verb(Var arglist, Byte next, void *vdata, Objid progr)
 {                             /* (object, info, args) */
***************
*** 193,198 ****
--- 389,405 ----
              || (progr != owner && !is_wizard(progr))) {
       free_str(names);
       e = E_PERM;
+ /*** -o_Verbs Patch ***/
+       } else if (!is_wizard(progr) && (flags & VF_NOT_O) && server_flag_option("protect_o_flag")) {
+               free_str(names);
+               e = E_PERM;
+       } else if (!is_wizard(owner) && name_conflict_with_ancestor(db_object_parent(oid), owner, names)) {
+               free_str(names);
+               e = E_PERM;
+       } else if ((flags & VF_NOT_O) && name_conflict_with_descendants(oid, owner, names)) {
+               free_str(names);
+               e = E_INVARG;
+ /*** -o_Verbs Patch ***/
     } else
       db_add_verb(oid, names, owner, flags, dobj, prep, iobj);

***************
*** 284,290 ****
     r.v.list[1].type = TYPE_OBJ;
     r.v.list[1].v.obj = db_verb_owner(h);
     r.v.list[2].type = TYPE_STR;
!     r.v.list[2].v.str = s = str_dup("xxxx");
     flags = db_verb_flags(h);
     if (flags & VF_READ)
       *s++ = 'r';
--- 491,499 ----
     r.v.list[1].type = TYPE_OBJ;
     r.v.list[1].v.obj = db_verb_owner(h);
     r.v.list[2].type = TYPE_STR;
! /*** -o_Verbs Patch ***/
!     r.v.list[2].v.str = s = str_dup("xxxxx");
! /*** end -o_Verbs Patch ***/
     flags = db_verb_flags(h);
     if (flags & VF_READ)
       *s++ = 'r';
***************
*** 294,299 ****
--- 503,512 ----
       *s++ = 'x';
     if (flags & VF_DEBUG)
       *s++ = 'd';
+  /*** -o_Verbs Patch ***/
+       if (!(flags & VF_NOT_O) && !server_flag_option("use_blocked_notation")) *s++ = 'o';
+       else if ((flags & VF_NOT_O) && server_flag_option("use_blocked_notation")) *s++ = 'b';
+  /*** end -o_Verbs Patch ***/
     *s = '\0';
     r.v.list[3].type = TYPE_STR;
     r.v.list[3].v.str = str_ref(db_verb_names(h));
***************
*** 333,339 ****
              || (!is_wizard(progr) && db_verb_owner(h) != new_owner)) {
       free_str(new_names);
       return make_error_pack(E_PERM);
!     }
     db_set_verb_owner(h, new_owner);
     db_set_verb_flags(h, new_flags);
     db_set_verb_names(h, new_names);
--- 546,577 ----
              || (!is_wizard(progr) && db_verb_owner(h) != new_owner)) {
       free_str(new_names);
       return make_error_pack(E_PERM);
! /*** -o_Verbs Patch ***/
!       } else if (!is_wizard(progr) && server_flag_option("protect_o_flag")
!                                 && ((new_flags & VF_NOT_O) != (db_verb_flags(h) & VF_NOT_O))) {
!               free_str(new_names);
!               return make_error_pack(E_PERM);
!       } else if ((new_owner != db_verb_owner(h) || mystrcasecmp(new_names, db_verb_names(h)))
!                                && !is_wizard(new_owner)
!                                && name_conflict_with_ancestor(db_object_parent(oid), new_owner, new_names))
! {
!               free_str(new_names);
!               return make_error_pack(E_PERM);
!       } else {
!                 /* ncwa mangles h sometimes... rematch it */
!                 h = find_described_verb(oid, desc);
!                 if ((new_flags & VF_NOT_O)
!                  && (new_owner != db_verb_owner(h)
!                      || !(db_verb_flags(h) & VF_NOT_O)
!                      || !mystrcasecmp(new_names, db_verb_names(h)))
!                                 && name_conflict_with_descendants(oid, new_owner, new_names)) {
!               free_str(new_names);
!               return make_error_pack(E_INVARG);
!                 }
!       }
! /* If ncwa can do it, so can ncwd.  Rematch again. */
!         h = find_described_verb(oid, desc);
! /*** end -o_Verbs Patch ***/
     db_set_verb_owner(h, new_owner);
     db_set_verb_flags(h, new_flags);
     db_set_verb_names(h, new_names);