1 /*
2 * queue.c - The queue command
3 *
4 * Queues allow for future batch processing
5 *
6 * Syntax: /QUEUE -DO -SHOW -LIST -NO_FLUSH -DELETE -FLUSH <name> {commands}
7 *
8 * Written by Jeremy Nelson
9 *
10 * Copyright (c) 1993 Jeremy Nelson.
11 * Copyright (c) 1993-2021 Matthew R. Green.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include "irc.h"
39 IRCII_RCSID("@(#)$eterna: queue.c,v 1.34 2021/02/27 08:02:14 mrg Exp $");
40
41 #include "alias.h"
42 #include "ircaux.h"
43 #include "debug.h"
44 #include "output.h"
45 #include "edit.h"
46 #include "if.h"
47 #include "queue.h"
48
49 typedef struct CmdListT
50 {
51 struct CmdListT *next;
52 u_char *what;
53 } CmdList;
54
55 typedef struct QueueT
56 {
57 struct QueueT *next;
58 struct CmdListT *first;
59 u_char *name;
60 } Queue;
61
62 static Queue *lookup_queue(Queue *, u_char *);
63 static CmdList *walk_commands(Queue *);
64 static Queue *make_new_queue(Queue *, u_char *);
65 static int add_commands_to_queue(Queue *, u_char *what, u_char *);
66 static int delete_commands_from_queue(Queue *, int);
67 static Queue *remove_a_queue(Queue *);
68 static void flush_queue(Queue *);
69 static Queue *do_queue(Queue *, int);
70 static void display_all_queues(Queue *);
71 static void print_queue(Queue *);
72 static int num_entries(Queue *);
73
74 void
queuecmd(u_char * cmd,u_char * args,u_char * subargs)75 queuecmd(u_char *cmd, u_char *args, u_char *subargs)
76 {
77 Queue *tmp;
78 u_char *arg = NULL,
79 *name = NULL,
80 *startcmds = NULL,
81 *cmds = NULL;
82 int noflush = 0,
83 runit = 0,
84 list = 0,
85 flush = 0,
86 remove_by_number = 0,
87 commands = 1,
88 number = 0;
89 static Queue *Queuelist = NULL;
90
91 /* If the queue list is empty, make an entry */
92 if (Queuelist == NULL) {
93 u_char *blah_c_sucks = UP("Top");
94
95 Queuelist = make_new_queue(NULL, blah_c_sucks);
96 }
97
98 if ((startcmds = my_index(args, '{')) == NULL) /* } */
99 commands = 0;
100 else
101 *(startcmds-1) = '\0';
102
103 while ((arg = upper(next_arg(args, &args))) != NULL)
104 {
105 if (*arg == '-')
106 {
107 *arg++ = '\0';
108 if (!my_strcmp(arg, "NO_FLUSH"))
109 noflush = 1;
110 else
111 if (!my_strcmp(arg, "SHOW"))
112 {
113 display_all_queues(Queuelist);
114 return;
115 }
116 else
117 if (!my_strcmp(arg, "LIST"))
118 list = 1;
119 else
120 if (!my_strcmp(arg, "DO"))
121 runit = 1;
122 else
123 if (!my_strcmp(arg, "DELETE"))
124 remove_by_number = 1;
125 else
126 if (!my_strcmp(arg, "FLUSH"))
127 flush = 1;
128 }
129 else
130 {
131 if (name)
132 number = my_atoi(arg);
133 else
134 name = arg;
135 }
136 }
137
138 if (name == NULL)
139 return;
140
141 /* Find the queue based upon the previous queue */
142 tmp = lookup_queue(Queuelist, name);
143
144 /* if the next queue is empty, then we need to see if
145 we should make it or output an error */
146 if ((tmp->next) == NULL)
147 {
148 if (commands)
149 tmp->next = make_new_queue(NULL, name);
150 else
151 {
152 yell ("QUEUE: (%s) no such queue",name);
153 return;
154 }
155 }
156 if (remove_by_number == 1)
157 {
158 if (delete_commands_from_queue(tmp->next, number))
159 tmp->next = remove_a_queue(tmp->next);
160 }
161 if (list == 1)
162 {
163 print_queue(tmp->next);
164 }
165 if (runit == 1)
166 {
167 tmp->next = do_queue(tmp->next, noflush);
168 }
169 if (flush == 1)
170 {
171 tmp->next = remove_a_queue(tmp->next);
172 }
173 if (startcmds)
174 {
175 int booya;
176
177 if ((cmds = next_expr(&startcmds, '{')) == NULL) /* } */
178 {
179 yell ("QUEUE: missing closing brace");
180 return;
181 }
182 booya = add_commands_to_queue (tmp->next, cmds, subargs);
183 say ("QUEUED: %s now has %d entries",name, booya);
184 }
185 }
186
187 /*
188 * returns the queue BEFORE the queue we are looking for
189 * returns the last queue if no match
190 */
191 static Queue *
lookup_queue(Queue * queue,u_char * what)192 lookup_queue(Queue *queue, u_char *what)
193 {
194 Queue *tmp = queue;
195
196 upper(what);
197
198 while (tmp->next)
199 {
200 if (!my_strcmp(tmp->next->name, what))
201 return tmp;
202 else
203 if (tmp->next)
204 tmp = tmp->next;
205 else
206 break;
207 }
208 return tmp;
209 }
210
211 /* returns the last CmdList in a queue, useful for appending commands */
212 static CmdList *
walk_commands(Queue * queue)213 walk_commands(Queue *queue)
214 {
215 CmdList *ctmp;
216
217 if (!queue)
218 return NULL;
219
220 ctmp = queue->first;
221 if (ctmp)
222 {
223 while (ctmp->next)
224 ctmp = ctmp->next;
225 return ctmp;
226 }
227 return NULL;
228 }
229
230 /*----------------------------------------------------------------*/
231 /* Make a new queue, link it in, and return it. */
232 static Queue *
make_new_queue(Queue * afterqueue,u_char * name)233 make_new_queue(Queue *afterqueue, u_char *name)
234 {
235 Queue *tmp;
236
237 if (!name)
238 return NULL;
239 tmp = new_malloc(sizeof *tmp);
240
241 tmp->next = afterqueue;
242 tmp->first = NULL;
243 tmp->name = NULL;
244 malloc_strcpy(&tmp->name, name);
245 upper(tmp->name);
246 return tmp;
247 }
248
249 /* add a command to a queue, at the end of the list */
250 /* expands the whole thing once and stores it */
251 static int
add_commands_to_queue(Queue * queue,u_char * what,u_char * subargs)252 add_commands_to_queue(Queue *queue, u_char *what, u_char *subargs)
253 {
254 CmdList *ctmp = walk_commands(queue);
255 u_char *list = NULL,
256 *sa;
257 int args_flag = 0;
258
259 sa = subargs ? subargs : (u_char *) " ";
260 list = expand_alias(NULL, what, sa, &args_flag, NULL);
261 if (!ctmp)
262 {
263 queue->first = new_malloc(sizeof(*queue->first));
264 ctmp = queue->first;
265 }
266 else
267 {
268 ctmp->next = new_malloc(sizeof(*ctmp->next));
269 ctmp = ctmp->next;
270 }
271 ctmp->what = NULL;
272 malloc_strcpy(&ctmp->what, list);
273 ctmp->next = NULL;
274 return num_entries(queue);
275 }
276
277
278 /*
279 * remove the Xth command from the queue. if 'which' is zero, then
280 * the whole queue is cleared.
281 */
282 static int
delete_commands_from_queue(Queue * queue,int which)283 delete_commands_from_queue(Queue *queue, int which)
284 {
285 CmdList *ctmp = queue->first;
286 CmdList *next;
287 int x;
288
289 if (which == 0)
290 {
291 for (; ctmp; ctmp = next)
292 {
293 new_free(&ctmp->what);
294 next = ctmp->next;
295 new_free(&ctmp);
296 }
297 queue->first = NULL;
298 return 0;
299 }
300 if (which == 1)
301 queue->first = ctmp->next;
302 else
303 {
304 for (x = 1; x < which - 1; x++)
305 {
306 if (ctmp->next)
307 ctmp = ctmp->next;
308 else
309 return 0;
310 }
311 if (ctmp->next == NULL)
312 {
313 say ("Could not find entry %d in %s queue", which,
314 queue->name);
315 return 0;
316 }
317 next = ctmp->next;
318 ctmp->next = ctmp->next->next;
319 ctmp = next;
320 }
321 new_free(&ctmp->what);
322 new_free(&ctmp);
323 if (queue->first == NULL)
324 return 1;
325 else
326 return 0;
327 }
328
329 /*-------------------------------------------------------------------*/
330 /* flush a queue, deallocate the memory, and return the next in line */
331 static Queue *
remove_a_queue(Queue * queue)332 remove_a_queue(Queue *queue)
333 {
334 Queue *tmp;
335
336 tmp = queue->next;
337 flush_queue(queue);
338 new_free(&queue);
339 return tmp;
340 }
341
342 /* walk through a queue, deallocating the entries */
343 static void
flush_queue(Queue * queue)344 flush_queue(Queue *queue)
345 {
346 CmdList *tmp,
347 *tmp2;
348
349 tmp = queue->first;
350
351 while (tmp != NULL)
352 {
353 tmp2 = tmp;
354 tmp = tmp2->next;
355 if (tmp2->what != NULL)
356 new_free(&tmp2->what);
357 if (tmp2)
358 new_free(&tmp2);
359 }
360 }
361
362 /*------------------------------------------------------------------------*/
363 /* run the queue, and if noflush, then return the queue, else return the
364 next queue */
365 static Queue *
do_queue(Queue * queue,int noflush)366 do_queue(Queue *queue, int noflush)
367 {
368 CmdList *tmp;
369
370 tmp = queue->first;
371
372 do
373 {
374 if (tmp->what != NULL)
375 parse_line(NULL, tmp->what, empty_string(), 0, 0, 0);
376 tmp = tmp->next;
377 }
378 while (tmp != NULL);
379
380 if (!noflush)
381 return remove_a_queue(queue);
382 else
383 return queue;
384 }
385
386 /* ---------------------------------------------------------------------- */
387 /* output the contents of all the queues to the screen */
388 static void
display_all_queues(Queue * queue)389 display_all_queues(Queue *queue)
390 {
391 Queue *tmp;
392
393 if (!queue)
394 return;
395
396 tmp = queue->next;
397 while (tmp)
398 {
399 print_queue(tmp);
400 if (tmp->next == NULL)
401 return;
402 else
403 tmp = tmp->next;
404 }
405 yell("QUEUE: No more queues");
406 }
407
408 /* output the contents of a queue to the screen */
409 static void
print_queue(Queue * queue)410 print_queue(Queue *queue)
411 {
412 CmdList *tmp;
413 int x = 0;
414
415 tmp = queue->first;
416 while (tmp != NULL)
417 {
418 if (tmp->what)
419 say ("<%s:%2d> %s",queue->name,++x,tmp->what);
420 tmp = tmp->next;
421 }
422 say ("<%s> End of queue",queue->name);
423 }
424
425 /* return the number of entries in a queue */
426 static int
num_entries(Queue * queue)427 num_entries(Queue *queue)
428 {
429 int x = 1;
430 CmdList *tmp;
431
432 if ((tmp = queue->first) == NULL)
433 return 0;
434 while (tmp->next)
435 {
436 x++;
437 tmp = tmp->next;
438 }
439 return x;
440 }
441