+/* Inserts a single entry into a message tree; must use this function
+ when inserting messages at runtime. */
+static void msg_tree_insert(struct MessageTree *mtree, int pfxlen,
+ char *key, struct Message *mptr)
+{
+ struct MessageTree *child;
+ int c;
+
+ if (!key[pfxlen])
+ {
+ mtree->msg = mptr;
+ return;
+ }
+ c = key[pfxlen];
+ child = mtree->pointers[c & (MAXPTRLEN-1)];
+ if(!child)
+ {
+ child = (struct MessageTree *)MyCalloc(1, sizeof(struct MessageTree));
+ mtree->pointers[c & (MAXPTRLEN-1)] = child;
+ }
+ msg_tree_insert(child, pfxlen+1, key, mptr);
+}
+
+/* Removes an entry from the message tree; suitable for use at runtime. */
+static struct MessageTree *msg_tree_remove(struct MessageTree *root, char *key)
+{
+ int c;
+
+ if (*key)
+ {
+ struct MessageTree *child = root->pointers[*key & (MAXPTRLEN-1)];
+ if (msg_tree_remove(child, key + 1))
+ return root;
+ root->pointers[*key & (MAXPTRLEN-1)] = NULL;
+ }
+ else
+ {
+ root->msg = NULL;
+ }
+ for (c = 0; c < MAXPTRLEN; ++c)
+ {
+ if (root->pointers[c])
+ return root;
+ }
+ MyFree(root);
+ return NULL;
+}
+
+/* Registers a service mapping to the pseudocommand handler. */
+int register_mapping(struct s_map *map)
+{
+ struct Message *msg;
+
+ if (msg_tree_parse(map->command, &msg_tree))
+ return 0;
+
+ msg = (struct Message *)MyMalloc(sizeof(struct Message));
+ msg->cmd = map->command;
+ msg->tok = map->command;
+ msg->count = 0;
+ msg->parameters = 2;
+ msg->flags = MFLG_SLOW | MFLG_EXTRA;
+ msg->bytes = 0;
+ msg->extra = map;
+
+ msg->handlers[UNREGISTERED_HANDLER] = m_ignore;
+ msg->handlers[CLIENT_HANDLER] = m_pseudo;
+ msg->handlers[SERVER_HANDLER] = m_ignore;
+ msg->handlers[OPER_HANDLER] = m_pseudo;
+ msg->handlers[SERVICE_HANDLER] = m_ignore;
+
+ /* Service mappings are only applicable to clients; insert the
+ pseudocommand into the command tree only. */
+ msg_tree_insert(&msg_tree, 0, msg->cmd, msg);
+ map->msg = msg;
+
+ return 1;
+}
+
+/* Removes a service mapping. */
+int unregister_mapping(struct s_map *map)
+{
+ if (!msg_tree_parse(map->command, &msg_tree))
+ {
+ /* This simply should never happen. */
+ assert(0);
+ return 0;
+ }
+
+ msg_tree_remove(&msg_tree, map->msg->cmd);
+
+ map->msg->extra = NULL;
+ MyFree(map->msg);
+ map->msg = NULL;
+
+ return 1;
+}
+