added cmd_invite and cmd_inviteme
authorpk910 <philipp@zoelle1.de>
Tue, 20 Sep 2011 20:45:06 +0000 (22:45 +0200)
committerpk910 <philipp@zoelle1.de>
Tue, 20 Sep 2011 20:55:37 +0000 (22:55 +0200)
bot_NeonServ.c
cmd_neonserv_invite.c [new file with mode: 0644]
cmd_neonserv_inviteme.c [new file with mode: 0644]
main.h

index c426cace6dcf9d63d1b897168e0d55c5dc3cee45..9c144bdf2b0b81dabf5934b5851156065beb3d84 100644 (file)
@@ -195,6 +195,13 @@ static const struct default_language_entry msgtab[] = {
     {"NS_UNBANALL_FAIL", "$b%s$b could not find any bans in %s."}, /* {ARGS: "NeonServ", "#TestChan"} */
     {"NS_UNBANME_DONE", "removed $b%d$b masks from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
     {"NS_UNBANME_FAIL", "$b%s$b could not find any bans matching %s."}, /* {ARGS: "NeonServ", "TestUser!TestIdent@TestUser.user.WebGamesNet"} */
+    {"NS_INVITE_RESTRICTION", "%s doesn't want to be invited to %s."},
+    {"NS_INVITE_TIMEOUT", "%s has already been invited to $b%s$b."},
+    {"NS_INVITE_ON_CHAN", "%s is already in $b%s$b."},
+    {"NS_INVITE_DONE_USER", "You have been invited to join $b%s$b by %s. (Do $b/msg %s %1$s uset noinvite 1$b if you don't want to be invited to %1$s anymore.)"},
+    {"NS_INVITE_DONE", "Invited $b%s$b to join %s."},
+    {"NS_INVITEME_ON_CHAN", "You are already in $b%s$b."},
+    {"NS_INVITEME_DONE", "You have been invited to join %s."},
     {NULL, NULL}
 };
 
@@ -244,7 +251,8 @@ INCLUDE ALL CMD's HERE
 //#include "cmd_neonserv_open.c"
 #include "cmd_neonserv_topic.c"
 #include "cmd_neonserv_mode.c"
-//#include "cmd_neonserv_invite.c"
+#include "cmd_neonserv_invite.c"
+#include "cmd_neonserv_inviteme.c"
 //#include "cmd_neonserv_info.c"
 #include "cmd_neonserv_netinfo.c"
 #include "cmd_neonserv_peek.c"
@@ -428,11 +436,12 @@ void init_NeonServ() {
     register_command(BOTID, "mode",         neonserv_cmd_mode,      1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_getop",       0);
     register_command(BOTID, "version",      neonserv_cmd_version,   0, 0,                                                                                           NULL,                   0);
     register_command(BOTID, "peek",         neonserv_cmd_peek,      0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN,                                              NULL,                   0);
-    //register_command(BOTID, "info",         neonserv_cmd_info,      0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN,                                              NULL,                   0);
     register_command(BOTID, "uset",         neonserv_cmd_uset,      0, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,                                                   NULL,                   0);
     register_command(BOTID, "unban",        neonserv_cmd_unban,     1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_canban",      0);
     register_command(BOTID, "unbanall",     neonserv_cmd_unbanall,  0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_canban",      0);
     register_command(BOTID, "unbanme",      neonserv_cmd_unbanme,   0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_canban",      0);
+    register_command(BOTID, "invite",       neonserv_cmd_invite,    1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_canop",       0);
+    register_command(BOTID, "inviteme",     neonserv_cmd_inviteme,  0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_getinvite",   0);
     
     register_command(BOTID, "trace",        neonserv_cmd_trace,     1, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,                                                   NULL,                   400);
     register_command(BOTID, "register",     neonserv_cmd_register,  2, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG,              NULL,                   100);
diff --git a/cmd_neonserv_invite.c b/cmd_neonserv_invite.c
new file mode 100644 (file)
index 0000000..e578cf9
--- /dev/null
@@ -0,0 +1,158 @@
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup);
+static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout);
+static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan);
+static int neonserv_cmd_invite_is_timeout(char *nick, char *chan);
+static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout);
+
+
+struct neonserv_cmd_invite_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+struct neonserv_cmd_invite_timeout {
+    char *nick;
+    char *chan;
+    
+    struct neonserv_cmd_invite_timeout *next;
+};
+
+static struct neonserv_cmd_invite_timeout *first_timeout = NULL, *last_timeout = NULL;
+
+static CMD_BIND(neonserv_cmd_invite) {
+    if(neonserv_cmd_invite_is_timeout(argv[0], chan->name)) {
+        reply(getTextBot(), user, "NS_INVITE_TIMEOUT", argv[0], chan->name);
+        return;
+    }
+    struct UserNode *cuser = getUserByNick(argv[0]);
+    if(!cuser) {
+        cuser = createTempUser(argv[0]);
+        cuser->flags |= USERFLAG_ISTMPUSER;
+    } else if(getChanUser(cuser, chan)) {
+        reply(getTextBot(), user, "NS_INVITE_ON_CHAN", cuser->nick, chan->name);
+        /* BUG
+         This check does not work if the user is invisible (CHMODE +D/+d)
+         to fix this we'd need to request the full userlist...
+         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
+        */
+        return;
+    }
+    if(cuser->flags & USERFLAG_ISAUTHED) {
+        neonserv_cmd_invite_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+    } else {
+        struct neonserv_cmd_invite_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->textclient = getTextBot();
+        cache->user = user;
+        cache->chan = chan;
+        cache->event = event;
+        cache->nick = strdup(argv[0]);
+        get_userauth(cuser, neonserv_cmd_invite_nick_lookup, cache);
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup) {
+    struct neonserv_cmd_invite_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    neonserv_cmd_invite_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : NULL));
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    if(auth) {
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //check if the user has set noinvite
+            printf_mysql_query("SELECT `id` FROM `noinvite` WHERE `uid` = '%s' AND `cid` = '%d'", row[0], chan->channel_id);
+            res = mysql_use();
+            if ((row = mysql_fetch_row(res)) != NULL) {
+                reply(textclient, user, "NS_INVITE_RESTRICTION", nick, chan->name);
+                return;
+            }
+        }
+    }
+    struct neonserv_cmd_invite_timeout *timeout = neonserv_cmd_invite_add_timeout(nick, chan->name);
+    timeq_add(INVITE_TIMEOUT, neonserv_cmd_invite_timeout_timeout, timeout);
+    putsock(client, "INVITE %s %s", nick, chan->name);
+    struct UserNode *tmpu = getUserByNick(nick);
+    if(!tmpu) {
+        tmpu = createTempUser(nick);
+        tmpu->flags |= USERFLAG_ISTMPUSER | (auth ? USERFLAG_ISAUTHED : 0);
+        if(auth)
+            strcpy(tmpu->auth, auth);
+    }
+    reply(textclient, tmpu, "NS_INVITE_DONE_USER", chan->name, user->nick, client->user->nick);
+    reply(textclient, user, "NS_INVITE_DONE", nick, chan->name);
+}
+
+static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout) {
+    struct neonserv_cmd_invite_timeout *entry = data;
+    neonserv_cmd_invite_del_timeout(entry);
+}
+
+static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan) {
+    struct neonserv_cmd_invite_timeout *entry = malloc(sizeof(*entry));
+    if (!entry) {
+        perror("malloc() failed");
+        return NULL;
+    }
+    entry->next = NULL;
+    entry->nick = strdup(nick);
+    entry->chan = strdup(chan);
+    if(last_timeout) {
+        last_timeout->next = entry;
+        last_timeout = entry;
+    } else {
+        last_timeout = entry;
+        first_timeout = entry;
+    }
+    return entry;
+}
+
+static int neonserv_cmd_invite_is_timeout(char *nick, char *chan) {
+    if(!first_timeout) return 0;
+    struct neonserv_cmd_invite_timeout *entry;
+    for(entry = first_timeout; entry; entry = entry->next) {
+        if(!stricmp(entry->nick, nick) && !stricmp(entry->chan, chan))
+            return 1;
+    }
+    return 0;
+}
+
+static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout) {
+    struct neonserv_cmd_invite_timeout *entry, *prev = NULL;
+    for(entry = first_timeout; entry; entry = entry->next) {
+        if(entry == timeout) {
+            if(prev)
+                prev->next = entry->next;
+            else
+                first_timeout = entry->next;
+            break;
+        } else
+            prev = entry;
+    }
+    if(last_timeout == timeout)
+        last_timeout = prev;
+    free(timeout->nick);
+    free(timeout->chan);
+    free(timeout);
+}
diff --git a/cmd_neonserv_inviteme.c b/cmd_neonserv_inviteme.c
new file mode 100644 (file)
index 0000000..e5c5319
--- /dev/null
@@ -0,0 +1,18 @@
+
+/*
+* no arguments
+*/
+
+static CMD_BIND(neonserv_cmd_inviteme) {
+    if(getChanUser(user, chan)) {
+        reply(getTextBot(), user, "NS_INVITEME_ON_CHAN", chan->name);
+        /* BUG
+         This check does not work if the user is invisible (CHMODE +D/+d)
+         to fix this we'd need to request the full userlist...
+         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
+        */
+        return;
+    }
+    putsock(client, "INVITE %s %s", user->nick, chan->name);
+    reply(getTextBot(), user, "NS_INVITEME_DONE", chan->name);
+}
diff --git a/main.h b/main.h
index 9aa15a0db0f9ea6d6d95c523698ce9b50e56322f..115d15e77631c04ba207b4cfc3d994bd52e96902 100644 (file)
--- a/main.h
+++ b/main.h
@@ -62,6 +62,7 @@
 #define MAXNUMPARAMS    200 /* maximum number of parameters in one line */
 #define MAXLANGUAGES    5
 #define MAXMODES        6
+#define INVITE_TIMEOUT  30
 
 //valid nick chars
 #define VALID_NICK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{|}~[\\]^-_`"