]> jfr.im git - solanum.git/blobdiff - modules/m_services.c
MODRESTART/MODRELOAD: Defer reloading more quickly
[solanum.git] / modules / m_services.c
index 24878ad1f040c2ffb6c9d1f1f018a1e5de4cd3e4..bf378600b7508258de0260a21c96e7f0132bd878 100644 (file)
@@ -25,8 +25,6 @@
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- *
- * $Id: m_services.c 1907 2006-08-29 19:18:15Z jilles $
  */
 
 #include "stdinc.h"
@@ -34,8 +32,7 @@
 #include "send.h"
 #include "channel.h"
 #include "client.h"
-#include "common.h"
-#include "config.h"
+#include "defaults.h"
 #include "ircd.h"
 #include "numeric.h"
 #include "s_conf.h"
@@ -47,6 +44,9 @@
 #include "modules.h"
 #include "whowas.h"
 #include "monitor.h"
+#include "supported.h"
+
+static const char services_desc[] = "Provides support for running a services daemon";
 
 static int _modinit(void);
 static void _moddeinit(void);
@@ -54,31 +54,31 @@ static void _moddeinit(void);
 static void mark_services(void);
 static void unmark_services(void);
 
-static int me_su(struct Client *, struct Client *, int, const char **);
-static int me_login(struct Client *, struct Client *, int, const char **);
-static int me_rsfnc(struct Client *, struct Client *, int, const char **);
-static int me_nickdelay(struct Client *, struct Client *, int, const char **);
+static void me_su(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
+static void me_login(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
+static void me_rsfnc(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
+static void me_nickdelay(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
 
-static void h_svc_server_introduced(hook_data_client *);
-static void h_svc_whois(hook_data_client *);
-static void h_svc_stats(hook_data_int *);
+static void h_svc_server_introduced(void *);
+static void h_svc_whois(void *);
+static void h_svc_stats(void *);
 static void h_svc_conf_read_start(void *);
 static void h_svc_conf_read_end(void *);
 
 struct Message su_msgtab = {
-       "SU", 0, 0, 0, MFLG_SLOW,
+       "SU", 0, 0, 0, 0,
        {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_su, 2}, mg_ignore}
 };
 struct Message login_msgtab = {
-       "LOGIN", 0, 0, 0, MFLG_SLOW,
+       "LOGIN", 0, 0, 0, 0,
        {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_login, 2}, mg_ignore}
 };
 struct Message rsfnc_msgtab = {
-       "RSFNC", 0, 0, 0, MFLG_SLOW,
+       "RSFNC", 0, 0, 0, 0,
        {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_rsfnc, 4}, mg_ignore}
 };
 struct Message nickdelay_msgtab = {
-       "NICKDELAY", 0, 0, 0, MFLG_SLOW,
+       "NICKDELAY", 0, 0, 0, 0,
        {mg_unreg, mg_ignore, mg_ignore, mg_ignore, {me_nickdelay, 3}, mg_ignore}
 };
 
@@ -86,32 +86,34 @@ mapi_clist_av1 services_clist[] = {
        &su_msgtab, &login_msgtab, &rsfnc_msgtab, &nickdelay_msgtab, NULL
 };
 mapi_hfn_list_av1 services_hfnlist[] = {
-       { "doing_stats",        (hookfn) h_svc_stats },
-       { "doing_whois",        (hookfn) h_svc_whois },
-       { "doing_whois_global", (hookfn) h_svc_whois },
-       { "server_introduced",  (hookfn) h_svc_server_introduced },
-       { "conf_read_start", (hookfn) h_svc_conf_read_start },
-       { "conf_read_end", (hookfn) h_svc_conf_read_end },
+       { "doing_stats",        h_svc_stats },
+       { "doing_whois",        h_svc_whois },
+       { "doing_whois_global", h_svc_whois },
+       { "server_introduced",  h_svc_server_introduced },
+       { "conf_read_start", h_svc_conf_read_start },
+       { "conf_read_end", h_svc_conf_read_end },
        { NULL, NULL }
 };
 
-DECLARE_MODULE_AV1(services, _modinit, _moddeinit, services_clist, NULL, services_hfnlist, "$Revision: 1907 $");
+DECLARE_MODULE_AV2(services, _modinit, _moddeinit, services_clist, NULL, services_hfnlist, NULL, NULL, services_desc);
 
 static int
 _modinit(void)
 {
        mark_services();
+       add_isupport("FNC", isupport_string, "");
        return 0;
 }
 
 static void
 _moddeinit(void)
 {
+       delete_isupport("FNC");
        unmark_services();
 }
 
-static int
-me_su(struct Client *client_p, struct Client *source_p,
+static void
+me_su(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
        int parc, const char *parv[])
 {
        struct Client *target_p;
@@ -120,85 +122,79 @@ me_su(struct Client *client_p, struct Client *source_p,
        {
                sendto_realops_snomask(SNO_GENERAL, L_ALL,
                        "Non-service server %s attempting to execute services-only command SU", source_p->name);
-               return 0;
+               return;
        }
 
        if((target_p = find_client(parv[1])) == NULL)
-               return 0;
+               return;
 
        if(!target_p->user)
-               return 0;
+               return;
 
        if(EmptyString(parv[2]))
                target_p->user->suser[0] = '\0';
        else
                rb_strlcpy(target_p->user->suser, parv[2], sizeof(target_p->user->suser));
 
-       sendto_common_channels_local_butone(target_p, CLICAP_ACCOUNT_NOTIFY, ":%s!%s@%s ACCOUNT %s",
+       sendto_common_channels_local(target_p, CLICAP_ACCOUNT_NOTIFY, NOCAPS, ":%s!%s@%s ACCOUNT %s",
                                            target_p->name, target_p->username, target_p->host,
                                            EmptyString(target_p->user->suser) ? "*" : target_p->user->suser);
 
-       invalidate_bancache_user(target_p);
+       if (MyClient(target_p))
+       {
+               if (EmptyString(target_p->user->suser))
+                       sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, target_p->name,
+                               target_p->name, target_p->username, target_p->host);
+               else
+                       sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, target_p->name,
+                               target_p->name, target_p->username, target_p->host, parv[2], parv[2]);
+       }
 
-       return 0;
+       invalidate_bancache_user(target_p);
 }
 
-static int
-me_login(struct Client *client_p, struct Client *source_p,
+static void
+me_login(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
        int parc, const char *parv[])
 {
        if(!IsPerson(source_p))
-               return 0;
+               return;
 
        rb_strlcpy(source_p->user->suser, parv[1], sizeof(source_p->user->suser));
-       return 0;
-}
-
-static int
-clean_nick(const char *nick)
-{
-       int len = 0;
-
-       if(EmptyString(nick) || *nick == '-' || IsDigit(*nick))
-               return 0;
-
-       for(; *nick; nick++)
-       {
-               len++;
-               if(!IsNickChar(*nick))
-                       return 0;
-       }
-
-       if(len >= NICKLEN)
-               return 0;
-
-       return 1;
 }
 
-static int
-me_rsfnc(struct Client *client_p, struct Client *source_p,
+/* me_rsfnc()
+ *     parv[1] = current user nickname
+ *     parv[2] = target nickname
+ *     parv[3] = new nickts
+ *     parv[4] = current nickts
+ *     parv[5] = optional; 0 (don't override RESVs) or 1 (override RESVs)
+ */
+static void
+me_rsfnc(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
        int parc, const char *parv[])
 {
        struct Client *target_p;
        struct Client *exist_p;
        time_t newts, curts;
-       char note[NICKLEN + 10];
+       struct nd_entry *nd;
+       char note[NAMELEN + 10];
 
        if(!(source_p->flags & FLAGS_SERVICE))
        {
                sendto_realops_snomask(SNO_GENERAL, L_ALL,
                        "Non-service server %s attempting to execute services-only command RSFNC", source_p->name);
-               return 0;
+               return;
        }
 
        if((target_p = find_person(parv[1])) == NULL)
-               return 0;
+               return;
 
        if(!MyClient(target_p))
-               return 0;
+               return;
 
-       if(!clean_nick(parv[2]))
-               return 0;
+       if(!clean_nick(parv[2], 0) || IsDigit(parv[2][0]))
+               return;
 
        curts = atol(parv[4]);
 
@@ -207,7 +203,13 @@ me_rsfnc(struct Client *client_p, struct Client *source_p,
         * nicknames before the RSFNC arrives.. --anfl
         */
        if(target_p->tsinfo != curts)
-               return 0;
+               return;
+
+       /* received a non-forced RSFNC for a nickname that is RESV.
+        * silently ignore it. ~jess
+        */
+       if(parc > 5 && atoi(parv[5]) == 0 && find_nick_resv(parv[2]))
+               return;
 
        if((exist_p = find_named_client(parv[2])))
        {
@@ -235,7 +237,7 @@ me_rsfnc(struct Client *client_p, struct Client *source_p,
                                        parv[2]);
                }
 
-               rb_snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
+               snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
                        me.name);
                exit_client(NULL, exist_p, &me, buf);
        }
@@ -258,25 +260,33 @@ doit:
                        target_p->name, parv[2], target_p->username,
                        target_p->host);
 
-       sendto_common_channels_local(target_p, NOCAPS, ":%s!%s@%s NICK :%s",
+       sendto_common_channels_local(target_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s",
                                target_p->name, target_p->username,
                                target_p->host, parv[2]);
 
-       add_history(target_p, 1);
+       whowas_add_history(target_p, 1);
        sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
                        use_id(target_p), parv[2], (long) target_p->tsinfo);
 
        del_from_client_hash(target_p->name, target_p);
+
+       /* invalidate nick delay because we're forcing this nick to be used */
+       nd = rb_dictionary_retrieve(nd_dict, parv[2]);
+       if (nd != NULL)
+               free_nd_entry(nd);
+
        rb_strlcpy(target_p->name, parv[2], NICKLEN);
        add_to_client_hash(target_p->name, target_p);
 
        monitor_signon(target_p);
 
-       del_all_accepts(target_p);
+       /* Make sure everyone that has this client on its accept list
+        * loses that reference.
+        */
+       del_all_accepts(target_p, false);
 
-       rb_snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name);
+       snprintf(note, sizeof(note), "Nick: %s", target_p->name);
        rb_note(target_p->localClient->F, note);
-       return 0;
 }
 
 /*
@@ -284,8 +294,8 @@ doit:
 **      parv[1] = duration in seconds (0 to remove)
 **      parv[2] = nick
 */
-static int
-me_nickdelay(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+static void
+me_nickdelay(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
 {
        int duration;
        struct nd_entry *nd;
@@ -294,13 +304,13 @@ me_nickdelay(struct Client *client_p, struct Client *source_p, int parc, const c
        {
                sendto_realops_snomask(SNO_GENERAL, L_ALL,
                        "Non-service server %s attempting to execute services-only command NICKDELAY", source_p->name);
-               return 0;
+               return;
        }
 
        duration = atoi(parv[1]);
        if (duration <= 0)
        {
-               nd = irc_dictionary_retrieve(nd_dict, parv[2]);
+               nd = rb_dictionary_retrieve(nd_dict, parv[2]);
                if (nd != NULL)
                        free_nd_entry(nd);
        }
@@ -309,17 +319,16 @@ me_nickdelay(struct Client *client_p, struct Client *source_p, int parc, const c
                if (duration > 86400)
                        duration = 86400;
                add_nd_entry(parv[2]);
-               nd = irc_dictionary_retrieve(nd_dict, parv[2]);
+               nd = rb_dictionary_retrieve(nd_dict, parv[2]);
                if (nd != NULL)
                        nd->expire = rb_current_time() + duration;
        }
-
-       return 0;
 }
 
 static void
-h_svc_server_introduced(hook_data_client *hdata)
+h_svc_server_introduced(void *data)
 {
+       hook_data_client *hdata = data;
        rb_dlink_node *ptr;
 
        RB_DLINK_FOREACH(ptr, service_list.head)
@@ -333,8 +342,9 @@ h_svc_server_introduced(hook_data_client *hdata)
 }
 
 static void
-h_svc_whois(hook_data_client *data)
+h_svc_whois(void *data_)
 {
+       hook_data_client *data = data_;
        char *p = data->target->user->suser;
        if(!EmptyString(p))
        {
@@ -354,12 +364,13 @@ h_svc_whois(hook_data_client *data)
 }
 
 static void
-h_svc_stats(hook_data_int *data)
+h_svc_stats(void *data_)
 {
+       hook_data_int *data = data_;
        char statchar = (char) data->arg2;
        rb_dlink_node *ptr;
 
-       if (statchar == 'U' && IsOper(data->client))
+       if (statchar == 'U' && IsOperGeneral(data->client))
        {
                RB_DLINK_FOREACH(ptr, service_list.head)
                {