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