started writing cmd_chanservsync
[NeonServV5.git] / cmd_neonserv_chanservsync.c
1
2 /*
3 * argv[0] - botnick
4 * argv[1] - key
5 */
6 #define CHANSERVSYNC_END_TIMEOUT 5
7
8 static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message);
9 static void neonserv_cmd_chanservsync_free_cache();
10
11 struct neonserv_cmd_chanservsync_cache {
12     struct ClientSocket *client, *textclient;
13     struct UserNode *user;
14     struct ChanNode *chan;
15     char *botnick;
16     time_t last_response;
17 };
18
19 struct neonserv_cmd_chanservsync_cache *neonserv_cmd_chanservsync_used = NULL;
20 const char* neonserv_cmd_chanservsync_supported[] = {"ChanServ", NULL};
21
22 static CMD_BIND(neonserv_cmd_chanservsync) {
23     if(neonserv_cmd_chanservsync_used && time(0) - neonserv_cmd_chanservsync_used->last_response < CHANSERVSYNC_END_TIMEOUT) {
24         reply(getTextBot(), user, "NS_CHANSERVSYNC_INUSE");
25         return;
26     }
27     if(neonserv_cmd_chanservsync_used) {
28         neonserv_cmd_chanservsync_free_cache();
29     }
30     char *botnick = "ChanServ";
31     char *key = "";
32     if(argc) {
33         if(argv[0][0] == '!') {
34             key = argv[0];
35         } else {
36             botnick = argv[0];
37             if(argc > 1)
38                 key = argv[1];
39         }
40     }
41     int seed = 0;
42     char *tmp;
43     char synckey[18];
44     for(tmp = user->auth; *tmp; tmp++)
45         seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
46     for(tmp = chan->name; *tmp; tmp++)
47         seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
48     for(tmp = botnick; *tmp; tmp++)
49         seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
50     sprintf(synckey, "!%08x!", seed);
51     if(strcmp(synckey, key)) {
52         int f = 0;
53         const char **supp = neonserv_cmd_chanservsync_supported;
54         while(*supp) {
55             if(!stricmp(*supp, botnick)) {
56                 f = 1;
57                 break;
58             }
59             supp++;
60         }
61         if(!f) {
62             reply(getTextBot(), user, "NS_CHANSERVSYNC_UNSUPPORTED", botnick, client->user->nick);
63         }
64         reply(getTextBot(), user, "NS_CHANSERVSYNC_KEY", client->user->nick, botnick, botnick, synckey);
65         return;
66     }
67     struct neonserv_cmd_chanservsync_cache *cache = malloc(sizeof(*cache));
68     if (!cache) {
69         perror("malloc() failed");
70         return;
71     }
72     cache->client = client;
73     cache->textclient = getTextBot();
74     cache->user = user;
75     cache->chan = chan;
76     cache->botnick = strdup(botnick);
77     cache->last_response = time(0);
78     neonserv_cmd_chanservsync_used = cache;
79     putsock(client, "PRIVMSG %s :users %s", botnick, chan->name);
80     bind_privnotice(neonserv_cmd_chanservsync_notice_listener);
81 }
82
83 static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message) {
84     if(neonserv_cmd_chanservsync_used && neonserv_cmd_chanservsync_used->client->user == target && !stricmp(user->nick, neonserv_cmd_chanservsync_used->botnick)) {
85         //we've got a notice from our bot...
86         //let's try parsing it....
87         char *p = message;
88         char *tokens[MAXLEN];
89         int tokensPos = 0;
90         while(*p == ' ') //skip leading spaces (airb0t)
91             p++;
92         message = p;
93         char *q = p;
94         while(*q) {
95             if(*q < 32) *q = ' ';
96             q++;
97         }
98         while((q = strstr(p, " "))) {
99             *q = '\0';
100             do {
101                 q++;
102             } while(*q == ' ');
103             if(*p) {
104                 tokens[tokensPos++] = p;
105             }
106             p = q;
107         }
108         if(*p) {
109             tokens[tokensPos++] = p;
110         }
111         if(tokensPos < 2) return;
112         int caccess = atoi(tokens[0]);
113         if(caccess < 1 || caccess > 500) return;
114         char *username = tokens[1];
115         int flags = 0;
116         time_t now = time(0);
117         time_t seen_time = now; //now - now = 0 (never)
118         neonserv_cmd_chanservsync_used->last_response = now;
119         if(strlen(username) < 3) return;
120         //ok we have access and username... maybe there is something else we can parse???
121         char *seen = NULL;
122         char *status = NULL;
123         if(tokensPos > 2) {
124             if(!stricmp("normal", tokens[2]) || !stricmp("suspended", tokens[2]) || !stricmp("bot", tokens[2])) {
125                 status = tokens[2];
126                 if (tokensPos > 3) {
127                     seen = merge_argv(tokens, 3, tokensPos);
128                 }
129             } else if (tokensPos > 3) {
130                 if(!stricmp("normal", tokens[tokensPos-1]) || !stricmp("suspended", tokens[tokensPos-1]) || !stricmp("bot", tokens[tokensPos-1])) {
131                     status = tokens[tokensPos-1];
132                     seen = merge_argv(tokens, 2, tokensPos-1);
133                 } else {
134                     seen = merge_argv(tokens, 2, tokensPos);
135                 }
136             } else {
137                 seen = merge_argv(tokens, 2, tokensPos);
138             }
139         }
140         if(status && !stricmp(status, "suspended")) {
141             flags |= DB_CHANUSER_SUSPENDED;
142         }
143         if(seen) {
144             if(!stricmp(seen, "here"))
145                 seen_time = 0;
146             else if(stricmp(seen, "never"))
147                 seen_time = strToTime(user, seen);
148         }
149         seen_time = now - seen_time;
150         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);
151     }
152 }
153
154 static void neonserv_cmd_chanservsync_free_cache() {
155     free(neonserv_cmd_chanservsync_used->botnick);
156     free(neonserv_cmd_chanservsync_used);
157     unbind_privnotice(neonserv_cmd_chanservsync_notice_listener);
158     neonserv_cmd_chanservsync_used = NULL;
159 }
160