fixed renameAccount function (merging mode)
[NeonServV5.git] / src / IRCQueue.c
1 /* IRCQueue.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 #include "IRCQueue.h"
18 #include "ClientSocket.h"
19 #include "IOHandler.h"
20
21 #define MAXPENALTY 8 /* 4 messages */
22
23 struct QueueEntry {
24     char *msg;
25     struct QueueEntry *next;
26 };
27
28 struct BotQueue {
29     struct ClientSocket *client;
30     struct IODescriptor *iofd;
31     int penalty : 8;
32     int rem_penalty : 8;
33     struct QueueEntry *fastqueue_first, *fastqueue_last;
34     struct QueueEntry *normalqueue_first, *normalqueue_last;
35     struct QueueEntry *textqueue_first, *textqueue_last;
36 };
37
38 static IOHANDLER_CALLBACK(queue_callback);
39
40 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
41     struct BotQueue *queue = malloc(sizeof(*queue));
42     if (!queue) {
43         perror("malloc() failed");
44         return NULL;
45     }
46     queue->client = client;
47     client->queue = queue;
48     queue->iofd = NULL;
49     queue->penalty = 0;
50     queue->fastqueue_first = NULL;
51     queue->fastqueue_last = NULL;
52     queue->normalqueue_first = NULL;
53     queue->normalqueue_last = NULL;
54     queue->textqueue_first = NULL;
55     queue->textqueue_last = NULL;
56     return queue;
57 }
58
59 static int calculate_penalty(char *message) {
60     int msglen = strlen(message);
61     int penalty = (2 + msglen / 100);
62     return penalty;
63 }
64
65 int queue_add(struct ClientSocket *client, char* msg, int len) {
66     if(!client->queue)
67         client->queue = initialize_queue(client);
68     struct BotQueue *queue = client->queue;
69     char *args = strstr(msg, " ");
70     int type;
71     int add_queue = 0;
72     if(args) {
73         *args = '\0';
74         if(!stricmp(msg, "MODE")) 
75             type = 3;
76         else if(!stricmp(msg, "KICK")) 
77             type = 3;
78         else if(!stricmp(msg, "PONG")) 
79             type = 3;
80         else if(!stricmp(msg, "PRIVMSG")) 
81             type = 1;
82         else if(!stricmp(msg, "NOTICE")) 
83             type = 1;
84         else if(!stricmp(msg, "WHO")) 
85             type = 1;
86         else
87             type = 2;
88         *args = ' ';
89     } else
90         type = 2;
91     
92     //check if we need to queue
93     switch(type) {
94     case 1:
95         if(queue->textqueue_first) {
96             add_queue = 1;
97             break;
98         }
99     case 2:
100         if(queue->normalqueue_first) {
101             add_queue = 1;
102             break;
103         }
104     case 3:
105         if(queue->fastqueue_first) {
106             add_queue = 1;
107             break;
108         }
109     default:
110         if(queue->penalty >= MAXPENALTY)
111             add_queue = 1;
112         break;
113     }
114     
115     if(!add_queue) {
116         int penalty = calculate_penalty(msg);
117         write_socket_force(client, msg, len);
118         queue->penalty += penalty;
119         if(!queue->iofd) {
120             struct timeval timeout;
121             gettimeofday(&timeout, NULL);
122             if(queue->penalty >= MAXPENALTY)
123                 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
124             else
125                 queue->rem_penalty = queue->penalty;
126             timeout.tv_sec += queue->rem_penalty;
127             queue->iofd = iohandler_timer(timeout, queue_callback);
128             queue->iofd->data = queue;
129         }
130     } else {
131         struct QueueEntry *entry = malloc(sizeof(*entry));
132         if (!entry) {
133             perror("malloc() failed");
134             return 0;
135         }
136         entry->msg = strdup(msg);
137         entry->next = NULL;
138         if(type == 1) { //low priority
139             if(queue->textqueue_last) {
140                 queue->textqueue_last->next = entry;
141                 queue->textqueue_last = entry;
142             } else {
143                 queue->textqueue_last = entry;
144                 queue->textqueue_first = entry;
145             }
146         } else if(type == 2) { //normal priority
147             if(queue->normalqueue_last) {
148                 queue->normalqueue_last->next = entry;
149                 queue->normalqueue_last = entry;
150             } else {
151                 queue->normalqueue_last = entry;
152                 queue->normalqueue_first = entry;
153             }
154         } else if(type == 3) { //high priority
155             if(queue->fastqueue_last) {
156                 queue->fastqueue_last->next = entry;
157                 queue->fastqueue_last = entry;
158             } else {
159                 queue->fastqueue_last = entry;
160                 queue->fastqueue_first = entry;
161             }
162         }
163     }
164     return 1;
165 }
166
167 static void dequeue_bot(struct ClientSocket *client) {
168     if(client->queue->penalty >= MAXPENALTY) return;
169     int penalty;
170     //try to send high priority messages
171     if(client->queue->fastqueue_first) {
172         do {
173             struct QueueEntry *entry = client->queue->fastqueue_first;
174             if(!entry->next)
175                 client->queue->fastqueue_last = NULL;
176             client->queue->fastqueue_first = client->queue->fastqueue_first->next;
177             penalty = calculate_penalty(entry->msg);
178             write_socket_force(client, entry->msg, strlen(entry->msg));
179             client->queue->penalty += penalty;
180             free(entry->msg);
181             free(entry);
182         } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
183     }
184     if(client->queue->penalty >= MAXPENALTY) return;
185     //try to send normal priority messages
186     if(client->queue->normalqueue_first) {
187         do {
188             struct QueueEntry *entry = client->queue->normalqueue_first;
189             if(!entry->next)
190                 client->queue->normalqueue_last = NULL;
191             client->queue->normalqueue_first = client->queue->normalqueue_first->next;
192             penalty = calculate_penalty(entry->msg);
193             write_socket_force(client, entry->msg, strlen(entry->msg));
194             client->queue->penalty += penalty;
195             free(entry->msg);
196             free(entry);
197         } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
198     }
199     if(client->queue->penalty >= MAXPENALTY) return;
200     //try to send low priority messages
201     if(client->queue->textqueue_first) {
202         do {
203             struct QueueEntry *entry = client->queue->textqueue_first;
204             if(!entry->next)
205                 client->queue->textqueue_last = NULL;
206             client->queue->textqueue_first = client->queue->textqueue_first->next;
207             penalty = calculate_penalty(entry->msg);
208             write_socket_force(client, entry->msg, strlen(entry->msg));
209             client->queue->penalty += penalty;
210             free(entry->msg);
211             free(entry);
212         } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
213     }
214 }
215
216 void queue_destroy(struct ClientSocket *client) {
217     if(!client->queue) return;
218     struct QueueEntry *entry, *next;
219     for(entry = client->queue->fastqueue_first; entry; entry = next) {
220         next = entry->next;
221         free(entry->msg);
222         free(entry);
223     }
224     for(entry = client->queue->normalqueue_first; entry; entry = next) {
225         next = entry->next;
226         free(entry->msg);
227         free(entry);
228     }
229     for(entry = client->queue->textqueue_first; entry; entry = next) {
230         next = entry->next;
231         free(entry->msg);
232         free(entry);
233     }
234     if(client->queue->iofd)
235         iohandler_close(client->queue->iofd);
236     free(client->queue);
237     client->queue = NULL;
238 }
239
240 static IOHANDLER_CALLBACK(queue_callback) {
241     struct BotQueue *queue = event->iofd->data;
242     switch(event->type) {
243     case IOEVENT_TIMEOUT:
244         queue->penalty -= queue->rem_penalty;
245         dequeue_bot(queue->client);
246         if(queue->penalty > 0) {
247             struct timeval timeout;
248             gettimeofday(&timeout, NULL);
249             if(queue->penalty >= MAXPENALTY)
250                 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
251             else
252                 queue->rem_penalty = queue->penalty;
253             timeout.tv_sec += queue->rem_penalty;
254             queue->iofd = iohandler_timer(timeout, queue_callback);
255             queue->iofd->data = queue;
256         } else {
257             queue->iofd = NULL;
258             queue->penalty = 0;
259         }
260         break;
261     default:
262         break;
263     }
264 }