Merge branch 'development'
[NeonServV5.git] / src / HandleInfoHandler.c
1 /* HandleInfoHandler.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "HandleInfoHandler.h"
19 #include "ClientSocket.h"
20 #include "UserNode.h"
21 #include "ChanNode.h"
22 #include "IRCEvents.h"
23 #include "tools.h"
24 #include "modules.h"
25 #include "log.h"
26
27 #define AUTHSERV_NICK "AuthServ"
28
29 #define MAXCALLBACKS 3
30
31 struct HandleInfoQueueEntry {
32     char *auth;
33     void *callback[MAXCALLBACKS];
34     int module_id[MAXCALLBACKS];
35     void *data[MAXCALLBACKS];
36     
37     struct HandleInfoQueueEntry *next;
38 };
39
40 static struct HandleInfoQueueEntry* addHandleInfoQueueEntry(struct ClientSocket *client) {
41     struct HandleInfoQueueEntry *entry = malloc(sizeof(*entry));
42     if (!entry)
43     {
44         printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
45         return NULL;
46     }
47     SYNCHRONIZE(cache_sync);
48     entry->next = NULL;
49     if(client->handleinfo_last)
50         client->handleinfo_last->next = entry;
51     else
52         client->handleinfo_first = entry;
53     client->handleinfo_last = entry;
54     DESYNCHRONIZE(cache_sync);
55     return entry;
56 }
57
58 static struct HandleInfoQueueEntry* getNextHandleInfoQueueEntry(struct ClientSocket *client, int freeEntry) {
59     if(!client->handleinfo_first) return NULL;
60     SYNCHRONIZE(cache_sync);
61     struct HandleInfoQueueEntry *entry = client->handleinfo_first;
62     if(freeEntry) {
63         client->handleinfo_first = entry->next;
64         if(entry == client->handleinfo_last) {
65             client->handleinfo_last = NULL;
66         }
67     }
68     DESYNCHRONIZE(cache_sync);
69     return entry;
70 }
71
72 void clear_handleinfoqueue(struct ClientSocket *client) {
73     if(!client->handleinfo_first) return;
74     SYNCHRONIZE(cache_sync);
75     struct HandleInfoQueueEntry *entry, *next;
76     for(entry = client->handleinfo_first; entry; entry = next) {
77         next = entry->next;
78         free(entry);
79     }
80     client->handleinfo_last = NULL;
81     client->handleinfo_first = NULL;
82     DESYNCHRONIZE(cache_sync);
83 }
84
85 void lookup_authname(char *auth, int module_id, authlookup_callback_t callback, void *data) {
86     struct ClientSocket *bot;
87     struct HandleInfoQueueEntry* entry;
88     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
89         for(entry = bot->handleinfo_first; entry; entry = entry->next) {
90             if(!stricmp(entry->auth, auth)) {
91                 int i = 0;
92                 for(i = 1; i < MAXCALLBACKS; i++) {
93                     if(!entry->callback[i]) {
94                         entry->callback[i] = callback;
95                         entry->module_id[i] = module_id;
96                         entry->data[i] = data;
97                         return;
98                     }
99                 }
100             }
101         }
102         if(bot->flags & SOCKET_FLAG_PREFERRED)
103             break;
104     }
105     if(bot == NULL) return;
106     entry = addHandleInfoQueueEntry(bot);
107     int i;
108     entry->auth = strdup(auth);
109     entry->callback[0] = callback;
110     entry->module_id[0] = module_id;
111     for(i = 1; i < MAXCALLBACKS; i++)
112         entry->callback[i] = NULL;
113     entry->data[0] = data;
114     for(i = 1; i < MAXCALLBACKS; i++)
115         entry->data[i] = NULL;
116     putsock(bot, "PRIVMSG " AUTHSERV_NICK " :ACCOUNTINFO *%s", auth);
117 }
118
119 static void recv_notice(struct UserNode *user, struct UserNode *target, char *message) {
120     if(stricmp(user->nick, AUTHSERV_NICK)) return;
121     struct ClientSocket *bot;
122     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
123         if(bot->user == target) break;
124     }
125     if(!bot) return;
126     char *auth = NULL;
127     int do_match = 0, exists = 0;
128     char *tmp;
129     time_t registered = time(0);
130     struct tm *timeinfo;
131     //messages to parse:
132     //  Account * has not been registered.
133     //  Account information for Skynet:
134     if(!match("Account * has not been registered.", message)) {
135         do_match = 1;
136         tmp = strstr(message, "\002");
137         auth = tmp+1;
138         tmp = strstr(auth, "\002");
139         *tmp = '\0';
140     } else if(!match("Account information for *", message)) {
141         do_match = 2;
142         exists = 1;
143         tmp = strstr(message, "\002");
144         auth = tmp+1;
145         tmp = strstr(auth, "\002");
146         *tmp = '\0';
147     } else if(!match("  Registered on: *", message)) {
148         do_match = 1;
149         exists = 1;
150         tmp = strstr(message, ": ");
151         tmp += 2;
152         timeinfo = localtime(&registered);
153         timeinfo->tm_year = 0;
154         //parse time
155         //Sat Nov 19 14:52:57 2011
156         tmp = strchr(tmp, ' ');
157         if(!tmp) goto errparse;
158         tmp++;
159         char *tmp2 = strchr(tmp, ' ');
160         if(!tmp2) goto errparse;
161         *tmp2 = '\0';
162         if(!stricmp(tmp, "Jan"))
163             timeinfo->tm_mon = 0;
164         else if(!stricmp(tmp, "Feb"))
165             timeinfo->tm_mon = 1;
166         else if(!stricmp(tmp, "Mar"))
167             timeinfo->tm_mon = 2;
168         else if(!stricmp(tmp, "Apr"))
169             timeinfo->tm_mon = 3;
170         else if(!stricmp(tmp, "May"))
171             timeinfo->tm_mon = 4;
172         else if(!stricmp(tmp, "Jun"))
173             timeinfo->tm_mon = 5;
174         else if(!stricmp(tmp, "Jul"))
175             timeinfo->tm_mon = 6;
176         else if(!stricmp(tmp, "Aug"))
177             timeinfo->tm_mon = 7;
178         else if(!stricmp(tmp, "Sep"))
179             timeinfo->tm_mon = 8;
180         else if(!stricmp(tmp, "Oct"))
181             timeinfo->tm_mon = 9;
182         else if(!stricmp(tmp, "Nov"))
183             timeinfo->tm_mon = 10;
184         else if(!stricmp(tmp, "Dec"))
185             timeinfo->tm_mon = 11;
186         tmp = tmp2 + 1;
187         tmp2 = strchr(tmp, ' ');
188         if(!tmp2) goto errparse;
189         *tmp2 = '\0';
190         timeinfo->tm_mday = atoi(tmp);
191         tmp = tmp2 + 1;
192         if(*tmp == ' ') tmp++;
193         tmp2 = strchr(tmp, ':');
194         if(!tmp2) goto errparse;
195         *tmp2 = '\0';
196         timeinfo->tm_hour = atoi(tmp);
197         tmp = tmp2 + 1;
198         tmp2 = strchr(tmp, ':');
199         if(!tmp2) goto errparse;
200         *tmp2 = '\0';
201         timeinfo->tm_min = atoi(tmp);
202         tmp = tmp2 + 1;
203         tmp2 = strchr(tmp, ' ');
204         if(!tmp2) goto errparse;
205         *tmp2 = '\0';
206         timeinfo->tm_sec = atoi(tmp);
207         tmp = tmp2 + 1;
208         timeinfo->tm_year = atoi(tmp) - 1900;
209         registered = mktime(timeinfo);
210     }
211     errparse:
212     
213     if(do_match) {
214         #ifdef HAVE_THREADS
215         unsigned int tid = (unsigned int) pthread_self_tid();
216         while(!clientsocket_parseorder_top(tid)) {
217             usleep(1000); //1ms
218         }
219         #endif
220         struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, ((do_match != 2) ? 1 : 0));
221         if(entry) {
222             if(do_match == 2) {
223                 free(entry->auth);
224                 entry->auth = strdup(auth);
225                 return;
226             }
227             authlookup_callback_t *callback;
228             int i;
229             for(i = 0; i < MAXCALLBACKS; i++) {
230                 callback = entry->callback[i];
231                 if(!callback) break;
232                 if(!entry->module_id[i] || module_loaded(entry->module_id[i]))
233                     callback(entry->auth, exists, registered, entry->data[i]);
234             }
235             free(entry->auth);
236             free(entry);
237         }
238     }
239 }
240
241 void init_handleinfohandler() {
242     bind_privnotice(recv_notice, 0);
243 }
244
245 void free_handleinfohandler() {
246     
247 }