diff --git a/src/server/testsuite/lyskomd.0/gen-15.py b/src/server/testsuite/lyskomd.0/gen-15.py
index dfd1ee79a22a2fe16ef1191aad09b79ce39132c6..5d41e70b8fb59c7ae40a9354cf39c25c8924f8dd 100644
--- a/src/server/testsuite/lyskomd.0/gen-15.py
+++ b/src/server/testsuite/lyskomd.0/gen-15.py
@@ -9,9 +9,12 @@ EXTENDED = 0
 DEBUG = 1
 
 class factory:
-    def __init__(self, bcc_trigg, bcc_visible, other_trigg, other_visible, rd):
+    def __init__(self, bcc_trigg, bcc_visible, bcc_author_visible,
+                 other_trigg, other_visible, rd):
         self.__bcc_trigg = bcc_trigg
         self.__bcc_visible = bcc_trigg + bcc_visible
+        self.__bcc_author_visible = (bcc_trigg + bcc_visible
+                                     + bcc_author_visible)
         self.__other_trigg = bcc_trigg + other_trigg
         self.__other_visible = bcc_trigg + other_trigg + other_visible
         for n in bcc_visible:
@@ -19,16 +22,18 @@ class factory:
                 self.__other_visible.append(n)
 	self.__readable = bcc_trigg + other_trigg + rd
 
-    def create(self, misc, conf, loc,
+    def create(self, author, misc, conf, loc,
                rec_time = None, sent_by = None, sent_at = None):
         if misc == 15:
             trigg = self.__bcc_trigg
             visib = self.__bcc_visible
+            author_visib = self.__bcc_author_visible
         else:
             trigg = self.__other_trigg
             visib = self.__other_visible
-        return misc_group(misc, conf, loc, trigg, visib, self.__readable,
-                          rec_time, sent_by, sent_at)
+            author_visib = self.__other_visible
+        return misc_group(misc, conf, loc, trigg, visib, author_visib,
+                          self.__readable, rec_time, sent_by, sent_at, author)
 
 
 def a_list_pattern(lst):
@@ -40,22 +45,36 @@ def a_list_pattern(lst):
 def a_list_rq(lst):
     return "%d { %s }" % (len(lst), string.join(lst, " "))
 
+class sequence_allocator:
+    def __init__(self, start):
+        self.curr = start
+
+    def next(self):
+        self.curr = self.curr + 1
+        return self.curr
 
 class misc_group:
-    def __init__(self, misc, conf, loc, trigg, visib, readable,
-                 rec_time, sent_by, sent_at):
+    def __init__(self, misc, conf, loc, trigg, visib, visib_by_author,
+                 readable, rec_time, sent_by, sent_at, author):
         self.__misc = misc
         self.__conf = conf
         self.__loc = loc
         self.__trigg = trigg
         self.__visib = visib
+        self.__visib_by_author = visib_by_author
 	self.__readable = readable
         self.__rec_time = rec_time
         self.__sent_by = sent_by
         self.__sent_at = sent_at
+        self.__author = author
+
+    def visible(self, viewer):
+        return (viewer in self.__visib
+                or (viewer == self.__author
+                    and viewer in self.__visib_by_author))
 
     def miscs(self, viewer):
-        if viewer not in self.__visib:
+        if not self.visible(viewer):
             return []
         res = ["%d %d" % (self.__misc, self.__conf),
                "6 %d" % self.__loc]
@@ -67,63 +86,93 @@ class misc_group:
             res.append("9 $any_time")
         return res
 
-    def async(self, viewer, txt):
-        if viewer not in self.__visib:
+    def async(self, viewer, text_no):
+        if not self.visible(viewer):
             return None
-        return "%d %d %d" % (txt, self.__conf, self.__misc)
+        return "%d %d %d" % (text_no, self.__conf, self.__misc)
 
     def trigger(self, viewer):
         return viewer in self.__trigg
 
     def readable(self, viewer):
         return viewer in self.__readable
- 
 
-# (creator, recipient): bcc-trigg, bcc-vis, other-trigg, other-vis, rd
+    def recipient(self):
+        return self.__conf
+
+    def recipient_type(self):
+        return self.__misc
+
+
+class text_stat:
+    tno = sequence_allocator(0)
+
+    def __init__(self, author):
+        self.__author = author
+        self.__misc_groups = []
+        self.__text_no = self.tno.next()
+
+    def add_misc_group(self, misc_grp):
+        assert isinstance(misc_grp, misc_group)
+        self.__misc_groups.append(misc_grp)
+
+    def author(self):
+        return self.__author
+
+    def misc_groups(self):
+        return self.__misc_groups[:]
+
+    def text_no(self):
+        return self.__text_no
+
+    def remove_misc_group(self, removed):
+        self.__misc_groups.remove(removed)
+
+# (creat, rcpt): bcc-trigg, bcc-vis, bcc-author-vis, other-trigg, other-vis, rd
 obj = { 
-    (6,  6): factory([6], [], [], [7, 8, 9], []),
-    (6,  7): factory([], [6, 7], [], [8, 9], [7]),
-    (6,  8): factory([8], [6], [], [7, 9], []),
-    (6,  9): factory([9], [6], [], [7, 8], []),
-    (6, 10): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (6, 11): factory([7, 8], [6], [], [9], []),
-    (6, 12): factory([7, 8], [6], [], [9], []),
-    (6, 13): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (6, 14): factory([7, 8], [6, 9], [], [], [9]),
-    (6, 15): factory([7, 8], [6, 9], [], [], [9]),
-
-    (7,  6): factory([6], [7], [], [8, 9], []),
-    (7,  7): factory([], [7], [], [6, 8, 9], [7]),
-    (7,  8): factory([8], [7], [], [6, 7, 9], []),
-    (7,  9): factory([9], [7], [], [6, 7, 8], []),
-    (7, 10): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (7, 11): factory([7, 8], [], [], [6, 9], []),
-    (7, 12): factory([7, 8], [], [], [], []),
-    (7, 13): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (7, 14): factory([7, 8], [9], [], [6], [9]),
-    (7, 15): factory([7, 8], [9], [], [], [9]),
-
-    (8,  6): factory([6], [8], [], [7, 9], []),
-    (8,  7): factory([], [7, 8], [], [6, 9], [7]),
-    (8,  8): factory([8], [], [], [6, 7, 9], []),
-    (8,  9): factory([9], [8], [], [6, 7], []),
-    (8, 10): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (8, 11): factory([7, 8], [], [], [6, 9], []),
-    (8, 12): factory([7, 8], [], [], [], []),
-    (8, 13): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (8, 14): factory([7, 8], [9], [], [6], [9]),
-    (8, 15): factory([7, 8], [9], [], [], [9]),
-
-    (9,  6): factory([6], [9], [], [7, 8], []),
-    (9,  7): factory([], [7, 9], [], [6, 8], [7]),
-    (9,  8): factory([8], [9], [], [6, 7], []),
-    (9,  9): factory([9], [], [], [6, 7, 8], []),
-    (9, 10): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (9, 11): factory([7, 8], [9], [], [6], []),
-    (9, 12): factory([7, 8], [9], [], [], []),
-    (9, 13): factory([7, 8], [6, 9], [], [], [6, 9]),
-    (9, 14): factory([7, 8], [9], [], [6], [9]),
-    (9, 15): factory([7, 8], [9], [], [], [9]),
+    (6,  6): factory([6], [], [7, 8, 9], [], [7, 8, 9], []),
+    (6,  7): factory([], [6, 7], [8, 9], [], [8, 9], [7]),
+    (6,  8): factory([8], [6], [7, 9], [], [7, 9], []),
+    (6,  9): factory([9], [6], [7, 8], [], [7, 8], []),
+    (6, 10): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (6, 11): factory([7, 8], [6], [9], [], [9], []),
+    (6, 12): factory([7, 8], [6], [], [], [9], []),
+    (6, 13): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (6, 14): factory([7, 8], [6, 9], [], [], [], [9]),
+    (6, 15): factory([7, 8], [6, 9], [], [], [], [9]),
+
+    (7,  6): factory([6], [7], [8, 9], [], [8, 9], []),
+    (7,  7): factory([], [7], [6, 8, 9], [], [6, 8, 9], [7]),
+    (7,  8): factory([8], [7], [6, 9], [], [6, 7, 9], []),
+    (7,  9): factory([9], [7], [6, 8], [], [6, 7, 8], []),
+    (7, 10): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (7, 11): factory([7, 8], [], [6, 9], [], [6, 9], []),
+    (7, 12): factory([7, 8], [], [], [], [], []),
+    (7, 13): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (7, 14): factory([7, 8], [9], [6], [], [6], [9]),
+    (7, 15): factory([7, 8], [9], [], [], [], [9]),
+
+    (8,  6): factory([6], [8], [7, 9], [], [7, 9], []),
+    (8,  7): factory([], [7, 8], [6, 9], [], [6, 9], [7]),
+    (8,  8): factory([8], [], [6, 7, 9], [], [6, 7, 9], []),
+    (8,  9): factory([9], [8], [6, 7], [], [6, 7], []),
+    (8, 10): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (8, 11): factory([7, 8], [], [6, 9], [], [6, 9], []),
+    (8, 12): factory([7, 8], [], [], [], [], []),
+    (8, 13): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (8, 14): factory([7, 8], [9], [6], [], [6], [9]),
+    (8, 15): factory([7, 8], [9], [], [], [], [9]),
+
+    (9,  6): factory([6], [9], [7, 8], [], [7, 8], []),
+    (9,  7): factory([], [7, 9], [6, 8], [], [6, 8], [7]),
+    (9,  8): factory([8], [9], [6, 7], [], [6, 7], []),
+    (9,  9): factory([9], [], [6, 7, 8], [], [6, 7, 8], []),
+    (9, 10): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (9, 11): factory([7, 8], [9], [6], [], [6], []),
+    (9, 12): factory([7, 8], [9], [], [], [], []),
+    (9, 13): factory([7, 8], [6, 9], [], [], [], [6, 9]),
+    (9, 14): factory([7, 8], [9], [6], [], [6], [9]),
+    (9, 15): factory([7, 8], [9], [], [], [], [9]),
 
     }
 
@@ -147,70 +196,68 @@ def talk_to(person):
 
 active_person = None
 
-class sequence_allocator:
-    def __init__(self, start):
-        self.curr = start
-
-    def next(self):
-        self.curr = self.curr + 1
-        return self.curr
-
 ref = sequence_allocator(999)
-tno = sequence_allocator(0)
-
+        
 def create(author, recipients):
-    misc = []
+    print
+    txt = text_stat(author)
     crea = []
     for (m, r) in recipients:
-        misc.append(obj[(author, r)].create(m, r, locno.alloc(r)))
+        txt.add_misc_group(obj[(author, r)].create(author, m, r,
+                                                   locno.alloc(r)))
         crea.append("%d %d" % (m, r))
     talk_to(author)
     cs = ref.next()
-    tx = tno.next()
+    print "# Creating text %d by %d" % (txt.text_no(), txt.author())
     print "send \"%d 86 [holl \"text %d\"] %s 0 { }\\n\"" % (
-        cs, tx, a_list_rq(crea))
-    new_text(author, tx, misc)
-    talk_to(author)
-    print "simple_expect \"=%d %d\"" % (cs, tx)
-    verify_text_stat(tx, author, misc)
-    return (tx, misc)
-
-def add_misc(author, txt, misc_type, rcpt, old_misc):
-    misc = obj[(author, rcpt)].create(misc_type, rcpt, locno.alloc(rcpt),
-                                      sent_at = 1)
+        cs, txt.text_no(), a_list_rq(crea))
+    new_text(txt)
     talk_to(author)
+    print "simple_expect \"=%d %d\"" % (cs, txt.text_no())
+    verify_text_stat(txt)
+    return txt
+
+def add_misc(adder, txt, misc_type, rcpt):
+    sent_by = None
+    if adder != txt.author():
+        sent_by = adder
+    misc = obj[(adder, rcpt)].create(txt.author(), misc_type, rcpt,
+                                     locno.alloc(rcpt),
+                                     sent_at = 1, sent_by = sent_by)
+    talk_to(adder)
     cs = ref.next()
-    print "send \"%d 30 %d %d %d\\n\"" % (cs, txt, rcpt, misc_type)
-    new_recipient(author, txt, misc, old_misc)
-    talk_to(author)
+    print "# Adding recipient to text %d; adder %d" % (txt.text_no(), adder)
+    print "send \"%d 30 %d %d %d\\n\"" % (cs, txt.text_no(), rcpt, misc_type)
+    new_recipient(adder, txt, misc)
+    talk_to(adder)
     print "simple_expect \"=%d\"" % cs
-    return misc
+    txt.add_misc_group(misc)
 
-def verify_text_stat(tx, author, misc):
+def verify_text_stat(txt):
     for p in PERSONS:
         talk_to(p)
-        print "send \"%d 90 %d\\n\"" % (ref.next(), tx)
-        visib = p == author
+        print "send \"%d 90 %d\\n\"" % (ref.next(), txt.text_no())
+        visib = p == txt.author()
         pattern = []
-        for m in misc:
+        for m in txt.misc_groups():
             pattern = pattern + m.miscs(p)
             if m.readable(p):
                 visib = 1
         if visib:
             print "simple_expect \"=%d $any_time " \
                   "%d 0 %d 0 %s 0 \\\\\\*\"" % (
-                ref.curr, author, len("text %d" % tx),
+                ref.curr, txt.author(), len("text %d" % txt.text_no()),
                 a_list_pattern(pattern))
         else:
-            print "simple_expect \"%%%d 14 %d\"" % (ref.curr, tx)
+            print "simple_expect \"%%%d 14 %d\"" % (ref.curr, txt.text_no())
 
 PERSONS = range(6, 10)
 
-def new_text(author, txt, misc):
+def new_text(txt):
     for viewer in PERSONS:
         sent = 0
         pattern = []
-        for m in misc:
+        for m in txt.misc_groups():
             if m.trigger(viewer):
                 sent = 1
             pattern = pattern + m.miscs(viewer)
@@ -218,20 +265,20 @@ def new_text(author, txt, misc):
             talk_to(viewer)
             print "simple_expect \":18 15 %d $any_time " \
                   "%d 0 %d 0 %s 0 \\\\\\*\"" % (
-                txt, author, len("text %d" % txt),
+                txt.text_no(), txt.author(), len("text %d" % txt.text_no()),
                 a_list_pattern(pattern))
-        elif author != viewer and DEBUG:
+        elif txt.author() != viewer and DEBUG:
             talk_to(viewer)
             print "send \"%d 35\\n\"" % ref.next()
             print "simple_expect \"=%d $any_time\"" % ref.curr
 
-def new_recipient(author, tx, misc, old_misc):
+def new_recipient(author, txt, misc):
     for viewer in PERSONS:
         sent = 0
-        for m in old_misc + [misc]:
+        for m in txt.misc_groups() + [misc]:
             if m.trigger(viewer):
                 sent = 1
-        async = misc.async(viewer, tx)
+        async = misc.async(viewer, txt.text_no())
         if sent and async != None:
             talk_to(viewer)
             print "simple_expect \":3 16 %s\"" % async
@@ -240,19 +287,20 @@ def new_recipient(author, tx, misc, old_misc):
             print "send \"%d 35\\n\"" % ref.next()
             print "simple_expect \"=%d $any_time\"" % ref.curr
 
-def delete(author, txt, misc):
+def delete(deleter, txt):
     nr = ref.next()
-    talk_to(author)
-    print "send \"%d 29 %d\\n\"" % (nr, txt)
-    deleted_text(author, txt, misc)
-    talk_to(author)
+    talk_to(deleter)
+    print "# Deleting text %d; deleter %d" % (txt.text_no(), deleter)
+    print "send \"%d 29 %d\\n\"" % (nr, txt.text_no())
+    deleted_text(deleter, txt)
+    talk_to(deleter)
     print "simple_expect \"=%d\"" % nr
 
-def deleted_text(author, txt, misc):
+def deleted_text(deleter, txt):
     for viewer in PERSONS:
         sent = 0
         pattern = []
-        for m in misc:
+        for m in txt.misc_groups():
             if m.trigger(viewer):
                 sent = 1
             pattern = pattern + m.miscs(viewer)
@@ -260,9 +308,41 @@ def deleted_text(author, txt, misc):
             talk_to(viewer)
             print "simple_expect \":18 14 %d $any_time " \
                   "%d 0 %d 0 %s 0 \\\\\\*\"" % (
-                txt, author, len("text %d" % txt),
+                txt.text_no(), txt.author(), len("text %d" % txt.text_no()),
                 a_list_pattern(pattern))
-        elif author != viewer and DEBUG:
+        elif deleter != viewer and DEBUG:
+            talk_to(viewer)
+            print "send \"%d 35\\n\"" % ref.next()
+            print "simple_expect \"=%d $any_time\"" % ref.curr
+
+
+def remove_misc(remover, txt, recip):
+    for removed in txt.misc_groups():
+        if removed.recipient() == recip:
+            break
+    else:
+        raise 'no-such-recipient'
+    nr = ref.next()
+    talk_to(remover)
+    print "# Removing recipient from text %d; remover %d" % (
+        txt.text_no(), remover)
+    print "send \"%d 31 %d %d\\n\"" % (nr, txt.text_no(), recip)
+    sub_recipient(remover, txt, recip, removed.recipient_type())
+    talk_to(remover)
+    print "simple_expect \"=%d\"" % nr
+    txt.remove_misc_group(removed)
+
+def sub_recipient(remover, txt, recip, misc_type):
+    for viewer in PERSONS:
+        sent = 0
+        for m in txt.misc_groups():
+            if m.trigger(viewer):
+                sent = 1
+        if sent:
+            talk_to(viewer)
+            print "simple_expect \":3 17 %d %d %s\"" % (
+                txt.text_no(), recip, misc_type)
+        elif remover != viewer and DEBUG:
             talk_to(viewer)
             print "send \"%d 35\\n\"" % ref.next()
             print "simple_expect \"=%d $any_time\"" % ref.curr
@@ -326,56 +406,70 @@ def disco():
     print "client_death %d" % (PERSONS[-1] - 6)
     print "lyskomd_death"
 
-setup()
-
-print "send_user \"testing simple create+delete\\n\""
-
-for author in [6, 7, 8, 9]:
-    for misc_type in [0, 1, 15]:
-        for rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
-            if author in [6, 9] and rcpt in [12, 15]:
-                continue
-            (txt, misc) = create(author, [(misc_type, rcpt)])
-            delete(author, txt, misc)
-            if not EXTENDED:
-                continue
-            for second_misc_type in [0, 1, 15]:
-                for second_rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
-                    if rcpt == second_rcpt:
-                        continue
-                    if author in [6, 9] and second_rcpt in [12, 15]:
-                        continue
-                    (txt, misc) = create(author, [
-                        (misc_type, rcpt),
-                        (second_misc_type, second_rcpt)])
-                    delete(author, txt, misc)
-
-print "send_user \"testing simple create+add+delete\\n\""
-
-for author in [6, 7, 8, 9]:
-    for misc_type in [0, 1, 15]:
-        for rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
-            if author in [6, 9] and rcpt in [12, 15]:
-                continue
-            (txt, misc) = create(author, []) 
-            misc.append(add_misc(author, txt, misc_type, rcpt, misc))
-            verify_text_stat(txt, author, misc)
-            delete(author, txt, misc)
-            if not EXTENDED:
-                continue
-            for second_misc_type in [0, 1, 15]:
-                for second_rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
-                    if rcpt == second_rcpt:
-                        continue
-                    if author in [6, 9] and second_rcpt in [12, 15]:
-                        continue
-                    (txt, misc) = create(author, [])
-                    misc.append(add_misc(author, txt, misc_type, rcpt, misc))
-                    verify_text_stat(txt, author, misc)
-                    misc.append(add_misc(author, txt,
-                                         second_misc_type, second_rcpt, misc))
-                    verify_text_stat(txt, author, misc)
-                    delete(author, txt, misc)
-
-
-disco()
+def simple_create_delete():
+    print "send_user \"testing simple create+delete\\n\""
+    for author in [6, 7, 8, 9]:
+        for misc_type in [0, 1, 15]:
+            for rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
+                if author in [6, 9] and rcpt in [12, 15]:
+                    continue
+                txt = create(author, [(misc_type, rcpt)])
+                delete(author, txt)
+                if not EXTENDED:
+                    continue
+                for second_misc_type in [0, 1, 15]:
+                    for second_rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
+                        if rcpt == second_rcpt:
+                            continue
+                        if author in [6, 9] and second_rcpt in [12, 15]:
+                            continue
+                        txt = create(author, [
+                            (misc_type, rcpt),
+                            (second_misc_type, second_rcpt)])
+                        delete(author, txt)
+
+def simple_create_add_delete():
+    print "send_user \"testing simple create+add+delete\\n\""
+
+    for author in [6, 7, 8, 9]:
+        for misc_type in [0, 1, 15]:
+            for rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
+                if author in [6, 9] and rcpt in [12, 15]:
+                    continue
+                txt = create(author, []) 
+                add_misc(author, txt, misc_type, rcpt)
+                verify_text_stat(txt)
+                delete(author, txt)
+                if not EXTENDED:
+                    continue
+                for second_misc_type in [0, 1, 15]:
+                    for second_rcpt in [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]:
+                        if rcpt == second_rcpt:
+                            continue
+                        if author in [6, 9] and second_rcpt in [12, 15]:
+                            continue
+                        txt = create(author, [])
+                        add_misc(author, txt, misc_type, rcpt)
+                        verify_text_stat(txt)
+                        add_misc(author, txt, second_misc_type, second_rcpt)
+                        verify_text_stat(txt)
+                        delete(author, txt)
+
+def special_cases():
+    print "send_user \"testing some special cases\\n\""
+
+    txt = create(7, [(0, 10)])
+    add_misc(6, txt, 15, 8)
+    verify_text_stat(txt)
+    remove_misc(7, txt, 10)
+    verify_text_stat(txt)
+    delete(7, txt)
+
+def generate_test():
+    setup()
+    simple_create_delete()
+    simple_create_add_delete()
+    special_cases()
+    disco()
+
+generate_test()