+static void
+check_umode_change(void *vdata)
+{
+ hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
+ bool changed = false;
+ struct Client *source_p = data->client;
+
+ if (!MyClient(source_p))
+ return;
+
+ if (data->oldumodes & UMODE_OPER && !IsOper(source_p))
+ source_p->umodes &= ~user_modes['M'];
+
+ changed = ((data->oldumodes ^ source_p->umodes) & user_modes['M']);
+
+ if (changed && source_p->umodes & user_modes['M'])
+ {
+ if (!HasPrivilege(source_p, "oper:message"))
+ {
+ sendto_one_notice(source_p, ":*** You need oper:message privilege for +M");
+ source_p->umodes &= ~user_modes['M'];
+ return;
+ }
+
+ update_session_deadline(source_p);
+ }
+ else if (changed)
+ {
+ // Unsetting +M; remove the timeout session
+ rb_dlink_node *n, *tn;
+
+ RB_DLINK_FOREACH_SAFE(n, tn, callerid_overriding_opers.head)
+ {
+ struct CallerIDOverrideSession *session_p = n->data;
+
+ if (session_p->client != source_p)
+ continue;
+
+ rb_dlinkDelete(n, &callerid_overriding_opers);
+ rb_free(session_p);
+ }
+ }
+}
+
+static void check_priv_change(void *vdata)
+{
+ hook_data_priv_change *data = (hook_data_priv_change*)vdata;
+ struct Client *source_p = data->client;
+ const char *fakeparv[4];
+
+ if (!MyClient(source_p))
+ return;
+
+ if (source_p->umodes & user_modes['M'] && !HasPrivilege(source_p, "oper:message"))
+ {
+ sendto_one_notice(source_p, ":*** You need oper:message privilege for +M");
+ fakeparv[0] = fakeparv[1] = source_p->name;
+ fakeparv[2] = "-M";
+ fakeparv[3] = NULL;
+ user_mode(source_p, source_p, 3, fakeparv);
+ }
+}
+
+static void
+handle_client_exit(void *vdata)
+{
+ hook_data_client_exit *data = (hook_data_client_exit *) vdata;
+ rb_dlink_node *n, *tn;
+ struct Client *source_p = data->target;
+
+ RB_DLINK_FOREACH_SAFE(n, tn, callerid_overriding_opers.head)
+ {
+ struct CallerIDOverrideSession *session_p = n->data;
+
+ if (session_p->client != source_p)
+ continue;
+
+ rb_dlinkDelete(n, &callerid_overriding_opers);
+ rb_free(session_p);
+ }
+}
+