{"NS_EXTTOPIC_INVALID_ID", "ADVANCEDTOPIC is enabled and \002%s\002 is an invalid TOPIC ID. Valid topic id's are: 1-9"},
{"NS_EXTTOPIC_TOPICID", "Topic %d: %s"},
{"NS_TOPIC_DONE", "Topic is now '%s'."},
+ {"NS_CHANSERVSYNC_UNSUPPORTED", "\0034WARNING\003: the user list style of %s is not known. %s can try to synchronize the userlist, but there is no guarantee that it is successful!"},
+ {"NS_CHANSERVSYNC_KEY", "If you really want to synchronize the %s userlist with %s use: chanservsync %s %s"},
+ {"NS_CHANSERVSYNC_INUSE", "\002chanservsync\002 is already in use by someone else. Please try again in a few seconds..."},
{NULL, NULL}
};
//#include "cmd_neonserv_resync.c"
//#include "cmd_neonserv_help.c"
//#include "cmd_neonserv_version.c"
+#include "cmd_neonserv_chanservsync.c"
//OPER CMD's
//#include "cmd_neonserv_bind.c"
register_command(BOTID, "delban", neonserv_cmd_delban, 1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "#channel_staticban", 0);
register_command(BOTID, "netinfo", neonserv_cmd_netinfo, 0, 0, NULL, 0);
register_command(BOTID, "topic", neonserv_cmd_topic, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "#channel_changetopic", 0);
+ register_command(BOTID, "chanservsync", neonserv_cmd_chanservsync, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "500", 0);
register_command(BOTID, "trace", neonserv_cmd_trace, 1, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, NULL, 400);
--- /dev/null
+
+/*
+* argv[0] - botnick
+* argv[1] - key
+*/
+#define CHANSERVSYNC_END_TIMEOUT 5
+
+static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message);
+static void neonserv_cmd_chanservsync_free_cache();
+
+struct neonserv_cmd_chanservsync_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct ChanNode *chan;
+ char *botnick;
+ time_t last_response;
+};
+
+struct neonserv_cmd_chanservsync_cache *neonserv_cmd_chanservsync_used = NULL;
+const char* neonserv_cmd_chanservsync_supported[] = {"ChanServ", NULL};
+
+static CMD_BIND(neonserv_cmd_chanservsync) {
+ if(neonserv_cmd_chanservsync_used && time(0) - neonserv_cmd_chanservsync_used->last_response < CHANSERVSYNC_END_TIMEOUT) {
+ reply(getTextBot(), user, "NS_CHANSERVSYNC_INUSE");
+ return;
+ }
+ if(neonserv_cmd_chanservsync_used) {
+ neonserv_cmd_chanservsync_free_cache();
+ }
+ char *botnick = "ChanServ";
+ char *key = "";
+ if(argc) {
+ if(argv[0][0] == '!') {
+ key = argv[0];
+ } else {
+ botnick = argv[0];
+ if(argc > 1)
+ key = argv[1];
+ }
+ }
+ int seed = 0;
+ char *tmp;
+ char synckey[18];
+ for(tmp = user->auth; *tmp; tmp++)
+ seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+ for(tmp = chan->name; *tmp; tmp++)
+ seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+ for(tmp = botnick; *tmp; tmp++)
+ seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+ sprintf(synckey, "!%08x!", seed);
+ if(strcmp(synckey, key)) {
+ int f = 0;
+ const char **supp = neonserv_cmd_chanservsync_supported;
+ while(*supp) {
+ if(!stricmp(*supp, botnick)) {
+ f = 1;
+ break;
+ }
+ supp++;
+ }
+ if(!f) {
+ reply(getTextBot(), user, "NS_CHANSERVSYNC_UNSUPPORTED", botnick, client->user->nick);
+ }
+ reply(getTextBot(), user, "NS_CHANSERVSYNC_KEY", client->user->nick, botnick, botnick, synckey);
+ return;
+ }
+ struct neonserv_cmd_chanservsync_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->chan = chan;
+ cache->botnick = strdup(botnick);
+ cache->last_response = time(0);
+ neonserv_cmd_chanservsync_used = cache;
+ putsock(client, "PRIVMSG %s :users %s", botnick, chan->name);
+ bind_privnotice(neonserv_cmd_chanservsync_notice_listener);
+}
+
+static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message) {
+ if(neonserv_cmd_chanservsync_used && neonserv_cmd_chanservsync_used->client->user == target && !stricmp(user->nick, neonserv_cmd_chanservsync_used->botnick)) {
+ //we've got a notice from our bot...
+ //let's try parsing it....
+ char *p = message;
+ char *tokens[MAXLEN];
+ int tokensPos = 0;
+ while(*p == ' ') //skip leading spaces (airb0t)
+ p++;
+ message = p;
+ char *q = p;
+ while(*q) {
+ if(*q < 32) *q = ' ';
+ q++;
+ }
+ while((q = strstr(p, " "))) {
+ *q = '\0';
+ do {
+ q++;
+ } while(*q == ' ');
+ if(*p) {
+ tokens[tokensPos++] = p;
+ }
+ p = q;
+ }
+ if(*p) {
+ tokens[tokensPos++] = p;
+ }
+ if(tokensPos < 2) return;
+ int caccess = atoi(tokens[0]);
+ if(caccess < 1 || caccess > 500) return;
+ char *username = tokens[1];
+ int flags = 0;
+ time_t now = time(0);
+ time_t seen_time = now; //now - now = 0 (never)
+ neonserv_cmd_chanservsync_used->last_response = now;
+ if(strlen(username) < 3) return;
+ //ok we have access and username... maybe there is something else we can parse???
+ char *seen = NULL;
+ char *status = NULL;
+ if(tokensPos > 2) {
+ if(!stricmp("normal", tokens[2]) || !stricmp("suspended", tokens[2]) || !stricmp("bot", tokens[2])) {
+ status = tokens[2];
+ if (tokensPos > 3) {
+ seen = merge_argv(tokens, 3, tokensPos);
+ }
+ } else if (tokensPos > 3) {
+ if(!stricmp("normal", tokens[tokensPos-1]) || !stricmp("suspended", tokens[tokensPos-1]) || !stricmp("bot", tokens[tokensPos-1])) {
+ status = tokens[tokensPos-1];
+ seen = merge_argv(tokens, 2, tokensPos-1);
+ } else {
+ seen = merge_argv(tokens, 2, tokensPos);
+ }
+ } else {
+ seen = merge_argv(tokens, 2, tokensPos);
+ }
+ }
+ if(status && !stricmp(status, "suspended")) {
+ flags |= DB_CHANUSER_SUSPENDED;
+ }
+ if(seen) {
+ if(!stricmp(seen, "here"))
+ seen_time = 0;
+ else if(stricmp(seen, "never"))
+ seen_time = strToTime(user, seen);
+ }
+ seen_time = now - seen_time;
+ reply(neonserv_cmd_chanservsync_used->textclient, neonserv_cmd_chanservsync_used->user, "\002PARSED LINE!\002 Access: %d User: %s Seen: %lu State: %d", caccess, username, (unsigned long) seen_time, flags);
+ }
+}
+
+static void neonserv_cmd_chanservsync_free_cache() {
+ free(neonserv_cmd_chanservsync_used->botnick);
+ free(neonserv_cmd_chanservsync_used);
+ unbind_privnotice(neonserv_cmd_chanservsync_notice_listener);
+ neonserv_cmd_chanservsync_used = NULL;
+}
+