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