939956e052e29b24d1b6433831a84130f0fa6f03
[NeonServV5.git] / src / IRCQueue.c
1 /* IRCQueue.c - NeonServ v5.1
2  * Copyright (C) 2011  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
20 #define MAXPENALTY 8 /* 4 messages */
21
22 struct QueueEntry {
23     char *msg;
24     struct QueueEntry *next;
25 };
26
27 struct BotQueue {
28     struct ClientSocket *client;
29     int penalty;
30     struct QueueEntry *fastqueue_first, *fastqueue_last;
31     struct QueueEntry *normalqueue_first, *normalqueue_last;
32     struct QueueEntry *textqueue_first, *textqueue_last;
33 };
34
35 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
36     struct BotQueue *queue = malloc(sizeof(*queue));
37     if (!queue) {
38         perror("malloc() failed");
39         return NULL;
40     }
41     queue->client = client;
42     client->queue = queue;
43     queue->penalty = 0;
44     queue->fastqueue_first = NULL;
45     queue->fastqueue_last = NULL;
46     queue->normalqueue_first = NULL;
47     queue->normalqueue_last = NULL;
48     queue->textqueue_first = NULL;
49     queue->textqueue_last = NULL;
50     return queue;
51 }
52
53 int queue_add(struct ClientSocket *client, char* msg, int len) {
54     if(!client->queue)
55         client->queue = initialize_queue(client);
56     struct BotQueue *queue = client->queue;
57     char *args = strstr(msg, " ");
58     int type;
59     if(args) {
60         *args = '\0';
61         if(!stricmp(msg, "MODE")) 
62             type = 3;
63         else if(!stricmp(msg, "KICK")) 
64             type = 3;
65         else if(!stricmp(msg, "PONG")) 
66             type = 3;
67         else if(!stricmp(msg, "PRIVMSG")) 
68             type = 1;
69         else if(!stricmp(msg, "NOTICE")) 
70             type = 1;
71         else if(!stricmp(msg, "WHO")) 
72             type = 1;
73         else
74             type = 2;
75         *args = ' ';
76     } else
77         type = 2;
78     struct QueueEntry *entry = malloc(sizeof(*entry));
79     if (!entry) {
80         perror("malloc() failed");
81         return 0;
82     }
83     entry->msg = strdup(msg);
84     entry->next = NULL;
85     if(type == 1) { //low priority
86         if(queue->textqueue_last) {
87             queue->textqueue_last->next = entry;
88             queue->textqueue_last = entry;
89         } else {
90             queue->textqueue_last = entry;
91             queue->textqueue_first = entry;
92         }
93     } else if(type == 2) { //normal priority
94         if(queue->normalqueue_last) {
95             queue->normalqueue_last->next = entry;
96             queue->normalqueue_last = entry;
97         } else {
98             queue->normalqueue_last = entry;
99             queue->normalqueue_first = entry;
100         }
101     } else if(type == 3) { //high priority
102         if(queue->fastqueue_last) {
103             queue->fastqueue_last->next = entry;
104             queue->fastqueue_last = entry;
105         } else {
106             queue->fastqueue_last = entry;
107             queue->fastqueue_first = entry;
108         }
109     }
110     return 1;
111 }
112
113 static int calculate_penalty(char *message) {
114     int msglen = strlen(message);
115     int penalty = (2 + msglen / 100);
116     return penalty;
117 }
118
119 static void dequeue_bot(struct ClientSocket *client) {
120     if(client->queue->penalty >= MAXPENALTY) return;
121     int penalty;
122     //try to send high priority messages
123     if(client->queue->fastqueue_first) {
124         do {
125             struct QueueEntry *entry = client->queue->fastqueue_first;
126             if(!entry->next)
127                 client->queue->fastqueue_last = NULL;
128             client->queue->fastqueue_first = client->queue->fastqueue_first->next;
129             penalty = calculate_penalty(entry->msg);
130             write_socket_force(client, entry->msg, strlen(entry->msg));
131             client->queue->penalty += penalty;
132             free(entry->msg);
133             free(entry);
134         } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
135     }
136     if(client->queue->penalty >= MAXPENALTY) return;
137     //try to send normal priority messages
138     if(client->queue->normalqueue_first) {
139         do {
140             struct QueueEntry *entry = client->queue->normalqueue_first;
141             if(!entry->next)
142                 client->queue->normalqueue_last = NULL;
143             client->queue->normalqueue_first = client->queue->normalqueue_first->next;
144             penalty = calculate_penalty(entry->msg);
145             write_socket_force(client, entry->msg, strlen(entry->msg));
146             client->queue->penalty += penalty;
147             free(entry->msg);
148             free(entry);
149         } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
150     }
151     if(client->queue->penalty >= MAXPENALTY) return;
152     //try to send low priority messages
153     if(client->queue->textqueue_first) {
154         do {
155             struct QueueEntry *entry = client->queue->textqueue_first;
156             if(!entry->next)
157                 client->queue->textqueue_last = NULL;
158             client->queue->textqueue_first = client->queue->textqueue_first->next;
159             penalty = calculate_penalty(entry->msg);
160             write_socket_force(client, entry->msg, strlen(entry->msg));
161             client->queue->penalty += penalty;
162             free(entry->msg);
163             free(entry);
164         } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
165     }
166 }
167
168 void queue_destroy(struct ClientSocket *client) {
169     if(!client->queue) return;
170     struct QueueEntry *entry, *next;
171     for(entry = client->queue->fastqueue_first; entry; entry = next) {
172         next = entry->next;
173         free(entry->msg);
174         free(entry);
175     }
176     for(entry = client->queue->normalqueue_first; entry; entry = next) {
177         next = entry->next;
178         free(entry->msg);
179         free(entry);
180     }
181     for(entry = client->queue->textqueue_first; entry; entry = next) {
182         next = entry->next;
183         free(entry->msg);
184         free(entry);
185     }
186     free(client->queue);
187     client->queue = NULL;
188 }
189
190 static struct timeval lastloop;
191 void queue_init() {
192     gettimeofday(&lastloop, NULL);
193 }
194
195
196 void queue_loop() {
197     struct ClientSocket *bot;
198     struct timeval now;
199     gettimeofday(&now, NULL);
200     long mtime, seconds, useconds;
201     seconds  = now.tv_sec  - lastloop.tv_sec;
202     useconds = now.tv_usec - lastloop.tv_usec;
203     mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
204     int fullseconds = mtime/1000;
205     if(fullseconds) {
206         lastloop.tv_sec += fullseconds;
207         for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
208             if(bot->queue && bot->queue->penalty) {
209                 bot->queue->penalty -= fullseconds;
210                 if(bot->queue->penalty < 0)
211                     bot->queue->penalty = 0;
212             }
213         }
214     }
215     for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
216         if(bot->queue)
217             dequeue_bot(bot);
218     }
219 }