Listing objects and permissions

Previous: Actually using all this XML to figure out a user's permissions ] [ Top: The user module ] [ Next: main.c: using the user module ]

In order to present nice menus and show our neat-o little folder system, we want a listing facility.

user_list()
The first step in listing things is the user_list function, which (given a user or group) produces a <user_list> XML structure. As usual, if any of the strings is NULL, that counts as a wildcard. I'm also including "." as a wildcard, as I don't expect classes, objects, or permissions named "." would be very useful anyway.
 
void _user_add_to_list (XML * ret, XML * user, const char * class, const char * object, const char * permission)
{
   XML * child;
   XML * piece;
   int ok;
   child = xml_firstelem (user);
   while (child) {
      if (!strcmp (child->name, "object")) {
         if ((!strcmp (class, ".") || !strcmp (class, xml_attrval (child, "class"))) &&
             (!strcmp (object, ".") || !strcmp (object, xml_attrval (child, "object"))) &&
             (!strcmp (permission, ".") ||
              _user_perm_cmp (xml_attrval (child, "permission"), permission))) {
               piece = xml_create ("object");
               xml_set (piece, "class", xml_attrval (child, "class"));
               xml_set (piece, "object", xml_attrval (child, "object"));
               xml_set (piece, "permission", xml_attrval (child, "permission"));
               xml_append (ret, piece);
         }
      } else if (!strcmp (child->name, "group-include")) {
         if (!strcmp (permission, ".") ||
             _user_perm_cmp (xml_attrval (child, "permission"), permission)) {
             piece = xml_create ("group-include");
             xml_set (piece, "name", xml_attrval (child, "name"));
             xml_set (piece, "permission", xml_attrval (child, "permission"));
             xml_append (ret, piece);
         }
      } else if (!strcmp (child->name, "group")) {
         piece = group_get (xml_attrval (child, "name"));
         if (piece) {
            _user_add_to_list (ret, piece, class, object, permission);
            xml_free (piece);
         }
      }
      child = xml_nextelem (child);
   }
}

XML * user_list (XML * user, const char * class, const char * object, const char * permission)
{
   XML * ret;

   ret = xml_create ("user_list");
   _user_add_to_list (ret, user, class ? class : ".", object ? object : ".", permission ? permission : ".");
   return (ret);
}


user_groups_list(): Get a list of groups to which a user belongs.
The next trick is to be able to list the groups to which a user belongs (regardless of permission level). This stashes everything into a flat list, from which it can be printed or whatever. As there's nothing in our group structure that prevents cycles, this function is rather paranoid when adding something to the list -- it checks to make sure it's not already there. This will have the salacious effect of not looping forever if there is a cycle.

The optional permission allows us to get a list of groups to which a user has a certain permission level. Groups to which the user actually belongs count as 'own' permission. Thus objects in that group are owned by the user.
 
void user_groups_list (XML * user, XML * holder, const char * permission)
{
   XML * elem;
   XML * check;
   XML * newone;
   XML * group;

   if (!permission) permission = "view";
   if (!*permission) permission = "view";

   elem = xml_firstelem (user);
   while (elem) {
      if (!strcmp (elem->name, "group") ||
            (!strcmp (elem->name, "group-include") &&
            _user_perm_cmp (xml_attrval (elem, "permission"), permission))) {
         check = xml_firstelem (holder);
         while (check) {
            if (!strcmp (xml_attrval (check, "name"), xml_attrval (elem, "name"))) break;
            check = xml_nextelem (check);
         }
         if (!check) {
            group = group_get (xml_attrval (elem, "name"));
            if (group) {
               newone = xml_create ("group");
               xml_set (newone, "name", xml_attrval (elem, "name"));
               xml_set (newone, "label", xml_attrval (elem, "label"));
               if (!*xml_attrval (newone, "label")) xml_set (newone, "label", xml_attrval (elem, "name"));

               xml_append (holder, newone);

               user_groups_list (group, holder, permission);
            }
            xml_free (group);
         }
      }

      elem = xml_nextelem (elem);
   }
}


group_users_list*(): listing users in (or out of) groups
To list users, we do pretty much the same thing as listing groups, except that we recurse along group-included-by instead of group-include. This recursion happens in this little helper function, which also tosses the groups visited into the list -- then our actual list routines can call this, and afterwards go through and delete those markers before returning the final list.
 
void _group_users_search (XML * group, XML * holder, const char * permission)
{
   XML * elem;
   XML * check;
   XML * newone;
   XML * othergroup;

   if (!permission) permission = "view";
   if (!*permission) permission = "view";

   elem = xml_firstelem (group);
   while (elem) {
      if (!strcmp (elem->name, "group-included-by") &&
          _user_perm_cmp (xml_attrval (elem, "permission"), permission)) {
         check = xml_firstelem (holder);
         while (check) {
            if (!strcmp (check->name, "group") &&
                !strcmp (xml_attrval (check, "name"), xml_attrval (elem, "name"))) break;
            check = xml_nextelem (check);
         }
         if (!check) {
            othergroup = group_get (xml_attrval (elem, "name"));
            if (othergroup) {
               newone = xml_create ("group");
               xml_set (newone, "name", xml_attrval (elem, "name"));

               xml_append (holder, newone);

               _group_users_search (othergroup, holder, permission);
            }
            xml_free (othergroup);
         }
      }

      if (!strcmp (elem->name, "user")) {
         check = xml_firstelem (holder);
         while (check) {
            if (!strcmp (check->name, "user") &&
                !strcmp (xml_attrval (check, "name"), xml_attrval (elem, "name"))) break;
            check = xml_nextelem (check);
         }
         if (!check) {
            newone = xml_create ("user");
            xml_set (newone, "name", xml_attrval (elem, "name"));
            xml_append (holder, newone);
         }
      }

      elem = xml_nextelem (elem);
   }
}
So OK, let's define our actual functions now.
 
void group_users_list (XML * group, XML * holder, const char * permission)
{
   XML * elem;

   _group_users_search (group, holder, permission);
   elem = xml_firstelem (holder);
   while (elem) {
      if (!strcmp (elem->name, "group")) {
         xml_delete (elem);
         elem = xml_firstelem (holder);
      } else {
         elem = xml_nextelem (elem);
      }
   }
}

void group_users_list_detailed (XML * group, XML * holder, const char * permission)
{
   XML * elem;
   XML * user;
   ATTR * attr;

   group_users_list (group, holder, permission);

   elem = xml_firstelem (holder);
   while (elem) {
      user = user_get (xml_attrval (elem, "name"));
      if (user) {
         attr = user->attrs;
         while (attr) {
            xml_set (elem, attr->name, attr->value);
            attr = attr->next;
         }
         xml_free (user);
      }
      elem = xml_nextelem (elem);
   }
}
Previous: Actually using all this XML to figure out a user's permissions ] [ Top: The user module ] [ Next: main.c: using the user module ]


This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.