incoming.c 28.6 KB
Newer Older
1 2 3 4 5 6 7 8
/*********************************************************
 *     The Milliways III System is copyright 1992        *
 *      J.S.Mitchell. (arthur@sugalaxy.swan.ac.uk)       *
 *       see licence for furthur information.            *
 *********************************************************/

#include <string.h>
#include <stdio.h>
9 10 11
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
12

13
#include "incoming.h"
14
#include "main.h"
15
#include "talker_privs.h"
16
#include "talker.h"
17
#include "special.h"
18
#include "rooms.h"
Chris Fry's avatar
Chris Fry committed
19
#include "alias.h"
Chris Fry's avatar
Chris Fry committed
20
#include "script.h"
21
#include "ipc.h"
22 23 24
#include "perms.h"
#include "mesg.h"
#include "echo.h"
25
#include "intl.h"
26
#include "bb.h"
27
#include "who.h"
28
#include "user.h"
29
#include "util.h"
30
#include "incoming.h"
31
#include "gaglist.h"
32 33
#include <jansson.h>
#include <str_util.h>
34

35
extern struct user * const user;
36
extern int quietmode;
37
extern ipc_connection_t *ipcsock;
38 39 40 41 42

int new_mail_waiting=0;
int mesg_waiting = 0;
char *mrod_user=NULL;

43 44 45
static int MesgStacked=0;
static int events_cancelled = 0;
static struct mstack *MesgStack=NULL;
46

47
static void accept_pipe_cmd(ipc_message_t *msg, struct user *mesg_user);
48
static void force_text(ipc_message_t *msg, const char *text, const char *from);
49
static void force_vtext(ipc_message_t *msg, const char *from, const char *format, ...) __attribute__((format (printf, 3, 4)));
50
static void force_ipc(char *text, char *from);
Chris Fry's avatar
Chris Fry committed
51
static void force_rpc(char *text, char *from);
52
static void force_checkonoff(char *text, char *from);
53
static void force_wiz(ipc_message_t *msg, char *text, char *from);
54
static void force_chatmode(char *text, unsigned long theirprivs, const char *from);
55
static void force_status(char *text, char *from);
56 57
static void force_channel(char *text, char *from, unsigned long theirprivs);
static void force_kick(char *text, char *from, unsigned long theirprivs);
58
static void force_gag(char *text, unsigned long theirprivs, const char *from);
59 60
static void zod(char *from, char *msg);
static void mrod(char *from, char *msg);
61
static void force_newmail(void);
62
static void force_protlevel(char *text, unsigned long theirprivs, const char *from);
63
static void force_protpower(char *text);
64

65 66
#define _MIN(a,b) (a<b)?a:b

67
void InsertMesg(struct mstack *new)
68 69 70 71 72 73
{
	new->next=NULL;
	if (MesgStack==NULL)
	{
		MesgStack=new;
		MesgStacked=1;
74
		events_cancelled = 0;
75 76 77 78 79 80
	}else
	{
		struct mstack *ptr;
		ptr=MesgStack;
		while (ptr->next!=NULL) ptr=ptr->next;
		ptr->next=new;
81
		/* Stack must be emptied before events can start again */
82 83
		if (events_cancelled)
			ptr->flags &= ~MST_EVENT;
84 85 86 87
		MesgStacked++;
	}
}

88 89 90 91 92 93 94 95 96 97 98 99 100
void StackMesg(char *text, char *from, int flags)
{
	struct mstack *new;
	new=(struct mstack *)malloc(sizeof(struct mstack));
	new->text=(char *)malloc(strlen(text)+1);
	new->from=(char *)malloc(strlen(from)+1);
	strcpy(new->text,text);
	strcpy(new->from,from);
	new->flags = flags;
	new->preamble = 0;
	InsertMesg(new);
}

101
static void StackEvent(char *text, char *from, int flags)
102 103 104 105 106 107 108 109 110 111 112 113
{
	struct mstack *new;
	new=(struct mstack *)malloc(sizeof(struct mstack));
	new->text=(char *)malloc(strlen(text)+1);
	new->from=(char *)malloc(strlen(from)+1);
	strcpy(new->text,text);
	strcpy(new->from,from);
	new->flags = MST_SCREV;
	new->preamble = flags;
	InsertMesg(new);
}

114 115
void ClearStack(void) {
	struct mstack *old;
116

117 118 119 120 121 122 123 124 125 126 127
	/* Nuke the entire stack */
	while (MesgStack!=NULL) {
		old=MesgStack;
		MesgStack=old->next;
		free(old->text);
		free(old->from);
		free(old);
	};
	MesgStacked=0;
}

128 129
void DisplayStack(void)
{
130 131 132
	struct mstack	*new;
	struct mstack	*old;
	char		*event_name;
133 134 135 136 137 138

	new=MesgStack;
	while (new!=NULL)
	{
		if (new->flags & MST_EVENT)
		{
139
			if (cp_test(user, CP_SCRIPT))
140 141
			{
				event_name = NULL;
142
				script_output=1;
143 144 145 146 147 148 149
				while ((event_name = NextLink(event_list, event_name)) != NULL)
				{
					ExecEvent(event_name, new->text, "text", new->from, new->preamble);
				}
				if (script_output) display_message(new->text, new->flags & MST_BEEP, 1);
				script_output = 1;
			}
150
			else display_message(new->text, new->flags & MST_BEEP, 1);
151
		}
152 153 154 155 156 157 158 159 160 161 162
		else if (new->flags & MST_SCREV)
		{
			switch(new->preamble)
			{
			case EST_RPC:
			{
				char *msg;
				char *funcname;
				char callfunc[MAXTEXTLENGTH];

				msg = remove_first_word(new->text);
163
				snprintf(callfunc, (MAXTEXTLENGTH-1<strlen(new->text))?MAXTEXTLENGTH-1:strlen(new->text) - strlen(msg), "%s", new->text);
164
				script_output=1;
165 166 167

				if ((funcname = FindLinks(rpc_list, callfunc)) != NULL)
				{
168
					ExecEvent(funcname, msg, "RPC", new->from, 0);
169
					free(funcname);
170 171 172 173 174
				}
				free(msg);
				break;
			}
			case EST_IPC:
175 176 177 178 179
			{
				char	*ipc_name;

				/* go through list of ipc functions */
				ipc_name = NULL;
180
				script_output=1;
181 182
				while ((ipc_name = NextLink(ipc_list, ipc_name)) != NULL)
				{
183
					ExecEvent(ipc_name, new->text, "IPC", new->from, 0);
184
				}
185
				break;
186
			}
187
			case EST_CHECKONOFF:
188
			{
189
				char	*aargs[6];
190
				char	*backup;
191 192
				char	*onoff_name, *sep, *head, *head2;
				char	*uname, *reason = NULL;
193
				int	ccode, method, isquiet;
194

195 196 197
				/* go through list and find checkonoff function */
				onoff_name = NULL;
				onoff_name = NextLink(onoff_list, onoff_name);
198

199 200 201 202 203 204 205 206 207 208 209
				/* if no function found, skip everything else */
				if (onoff_name == NULL) break;

				/* backup the input text */
				backup = strdup(new->text);

				/* get the first comma in the checkonoff code */
				sep = strchr(new->text, ',');

				/* if this comma does not exist, use the original version of checkonoff */
				if (sep == NULL)
210 211
				{
					/* simply convert to a number */
212
					ccode = atoi(new->text);
213 214

					/* due to backwards compatibility issues, we can only use 0 or 1 */
215 216
					if (ccode < 0) { free(backup); break; }
					if (ccode > 1) { free(backup); break; }
217 218 219 220 221 222 223

					/* create memory for argument strings */
					aargs[0] = malloc(sizeof(char) * 13);
					aargs[1] = malloc(sizeof(char) * 13);
					aargs[2] = malloc(sizeof(char) * 3);
					aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
					aargs[4] = malloc(sizeof(char) * 3);
224
					aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
225 226

					/* set up the argument strings */
227
					snprintf(aargs[0], 12, "%d", ccode);
228 229 230 231
					aargs[1][0] = 0;
					aargs[2][0] = 0;
					aargs[3][0] = 0;
					snprintf(aargs[4], 2, "1");
232
					aargs[5][0] = 0;
233 234

					/* run the event */
235
					ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
236 237 238 239 240 241 242 243

					/* free memory and break out */
					free(backup);
					free(aargs[0]);
					free(aargs[1]);
					free(aargs[2]);
					free(aargs[3]);
					free(aargs[4]);
244
					free(aargs[5]);
245
					break;
246 247
				}

248 249 250 251 252
				/* set head to the character after the comma, and terminate the code before the comma */
				head = sep + 1;
				*sep = 0;

				/* get the checkonoff code number */
253
				ccode = atoi(new->text);
254 255 256 257 258

				/* get the next comma in the checkonoff code */
				sep = strchr(head, ',');
				/* if no comma found, then this must be an interim checkonoff */
				if (sep == NULL)
259
				{
260
					/* due to backwards compatibility issues, we can only use 0 or 1 */
261 262
					if (ccode < 0) { free(backup); break; }
					if (ccode > 1) { free(backup); break; }
263 264 265 266 267 268 269 270 271 272

					/* simply convert the next argument to a number */
					isquiet = atoi(head);

					/* create memory for argument strings */
					aargs[0] = malloc(sizeof(char) * 13);
					aargs[1] = malloc(sizeof(char) * 13);
					aargs[2] = malloc(sizeof(char) * 3);
					aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
					aargs[4] = malloc(sizeof(char) * 3);
273
					aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
274 275

					/* set up the argument strings */
276
					snprintf(aargs[0], 12, "%d", ccode);
277 278 279 280
					aargs[1][0] = 0;
					snprintf(aargs[2], 2, "%d", isquiet);
					aargs[3][0] = 0;
					snprintf(aargs[4], 2, "2");
281
					aargs[5][0] = 0;
282 283

					/* run the event */
284
					ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
285 286 287 288 289 290 291 292

					/* free memory and break out */
					free(backup);
					free(aargs[0]);
					free(aargs[1]);
					free(aargs[2]);
					free(aargs[3]);
					free(aargs[4]);
293
					free(aargs[5]);
294
					break;
295
				}
296 297 298 299 300 301 302 303 304 305 306 307

				/* set second text head to the character after the comma, and terminate the method before the comma */
				head2 = sep + 1;
				*sep = 0;

				/* get the checkonoff method number */
				method = atoi(head);

				/* get the next comma in the checkonoff code */
				sep = strchr(head2, ',');
				/* if no comma found, then this must be broken! */
				if (sep == NULL)
308
				{
309 310 311
					printf("Invalid checkonoff broadcast received! (%s)\n", backup);
					free(backup);
					break;
312
				}
313

314
				/* set uname to the character after the comma, and terminate the method before the comma */
315 316 317 318 319 320
				uname = sep + 1;
				*sep = 0;

				/* get the checkonoff quiet flagr */
				isquiet = atoi(head2);

321 322 323 324 325 326 327 328 329
				/* get the optional next comma in the checkonoff code */
				sep = strchr(uname, ',');
				/* if comma is found, then the reason is there */
				if (sep != NULL)
				{
					reason = sep + 1;
					*sep = 0;
				}

330
				/* limit the method information */
331
				switch (ccode)
332
				{
333 334
				/* leave the talker */
				case 0:
335
					if (!cp_test(user, CP_CANZOD) && (method == 1))
336 337 338 339
					{
						method = 0;
						uname = new->from;
					}
340
					if (!u_god(user) && (method == 2))
341 342 343 344 345 346 347
					{
						method = 0;
						uname = new->from;
					}
					break;
				/* enter the talker */
				case 1:
348
					if (!cp_test(user, CP_SUMMON) && (method == 1))
349 350 351 352
					{
						method = 0;
						uname = new->from;
					}
353
					if (!u_god(user) && (method == 2))
354 355 356 357 358 359 360
					{
						method = 0;
						uname = new->from;
					}
					break;
				/* leave the board */
				case 2:
361
					if (!cp_test(user, CP_CANMROD) && (method == 3))
362 363 364 365
					{
						method = 0;
						uname = new->from;
					}
366
					if (!u_god(user) && ((method == 4) || (method == 5) || (method == 6)))
367 368 369 370 371 372 373 374
					{
						method = 0;
						uname = new->from;
					}
					break;
				/* enter the board */
				case 3:
					break;
375
				}
376

377 378 379 380 381 382
				/* create memory for argument strings */
				aargs[0] = malloc(sizeof(char) * 13);
				aargs[1] = malloc(sizeof(char) * 13);
				aargs[2] = malloc(sizeof(char) * 3);
				aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
				aargs[4] = malloc(sizeof(char) * 3);
383
				aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
384 385

				/* set up the argument strings */
386
				snprintf(aargs[0], 12, "%d", ccode);
387 388 389 390
				snprintf(aargs[1], 12, "%d", method);
				snprintf(aargs[2], 2, "%d", isquiet);
				snprintf(aargs[3], NAMESIZE, "%s", uname);
				snprintf(aargs[4], 2, "3");
391 392
				if (reason) snprintf(aargs[5], MAXTEXTLENGTH - 1, "%s", reason);
				else aargs[5][0] = 0;
393 394

				/* display the broadcast message */
395
				ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
396 397

				/* free up the memory used */
398 399
				free(aargs[0]);
				free(aargs[1]);
400 401 402
				free(aargs[2]);
				free(aargs[3]);
				free(aargs[4]);
403
				free(aargs[5]);
404
				free(backup);
405
				break;
406
			}
407 408 409 410
			default:
				break;
			}
		}
411
		else display_message(new->text, new->flags & MST_BEEP, 1);
412 413 414 415 416 417 418 419 420 421 422

		free(new->text);
		free(new->from);
		old=new->next;
		free(new);
		MesgStacked--;
		new=old;
	}
	MesgStack=NULL;
}

423
int MesgIsStacked(void)
424 425 426 427 428 429
{
	return (MesgStacked > 0);
}

void handle_mesg()
{
430
	static struct user mesg_user;
431 432

	mesg_waiting = 0;
433

434 435 436
	ipc_message_t * msg = read_socket(ipcsock, 1);

	while (msg != NULL) {
437
		if (msg->head.src == SYSTEM_USER) {
438
			strcpy(mesg_user.record.name,"System");
439 440
		} else if (fetch_user(&mesg_user, msg->head.src) != 0) {
			return;
441
		}
442
		accept_pipe_cmd(msg, &mesg_user);
443 444

		msg = read_socket(ipcsock, 0);
445
	}
446 447 448 449 450 451 452
	if (msg == NULL && !ipc_connected()) {
		if (ipcsock->fd != -1) {
			close(ipcsock->fd);
			ipcsock->fd = -1;
		}
		fprintf(stderr, "Server disconnected.\n");
	}
453
	if (cm_test(user, CM_ONCHAT))
Andrew Price's avatar
Andrew Price committed
454 455 456
		set_talk_rights();
	else
		set_rights();
457 458
}

459 460 461 462 463
static void force_lastread(const char * newbuff) {
	int fol;
	int pos;

	sscanf(newbuff,"%d:%d",&fol,&pos);
Andrew Price's avatar
Andrew Price committed
464
	user->record.lastread[fol] = pos;
465
}
466

467 468 469 470 471 472 473 474
static void display_uptime(ipc_message_t *msg)
{
	json_t * j = json_init(msg);
	const char *version = json_getstring(j, "version");
	const int uptime = json_getint(j, "uptime");

	printf("Server version: %s\n", version);
	printf("Server uptime: %s\n", itime(uptime));
475 476 477
	json_decref(j);
}

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
/** Server sent us an error, usually pretty fatal */
static void handle_ipc_error(ipc_message_t *msg)
{
	json_t * j = json_init(msg);
	const char * type = json_getstring(j, "error");

	if (strcasecmp(type, "NONCE")==0) {
		printf("Incompatible server version. Quitting.\n");
	} else {
		printf("Undefined server error '%s'\n", type);
	}
	json_decref(j);
	close_down(0, NULL, NULL);
}

493 494 495 496 497 498 499 500 501 502 503
static void display_error(ipc_message_t *msg)
{
	json_t * j = json_init(msg);
	const char * type = json_getstring(j, "type");
	const char * text = json_getstring(j, "text");

	char buff[MAXTEXTLENGTH];
	char * tb = buff;
	int len = MAXTEXTLENGTH;

	if (msg->head.type == IPC_TALKERROR) {
504
		snprintf(tb, len, "Talker error: %s", text);
505
	} else {
506
		snprintf(tb, len, "Unknown %s error: %s", type, text);
507 508
	}

509
	force_text(msg, buff, "System");
510 511 512 513
	json_decref(j);
}


514 515 516
/* handle formatted message */
static void display_content(ipc_message_t *msg)
{
517
	int32_t msg_posn = -1;
518
	struct user msg_user;
519 520
	const char *whom = NULL;

521
	if (msg->head.src == SYSTEM_USER) {
522
		whom = "System";
523 524
	} else {
		msg_posn = msg->head.src;
525 526
		if (fetch_user(&msg_user, msg_posn) != 0)
			return;
527
		whom = msg_user.record.name;
528
	}
529

530
	json_t * j = json_init(msg);
531

532
	if (msg->head.type == IPC_SAYTOROOM) {
533 534 535
		const char * type = json_getstring(j, "type");
		const char * text = json_getstring(j, "text");

536 537
		if (type == NULL) type="unknown";
	       	if (text == NULL) {
538 539 540 541 542 543 544 545 546 547
			printf("Invalid SAYTOROOM message from %s.\n", whom);
			json_decref(j);
			return;
		}

		char buff[MAXTEXTLENGTH];
		char * tb = buff;
		int len = MAXTEXTLENGTH;

		/* we have global on, prepend the channel number */
548
		if (cm_test(user, CM_GLOBAL)) {
549 550 551 552 553 554 555 556 557 558 559
			snprintf(tb, len, "%d:", msg->head.dst);
			int s = strlen(tb);
			len -= s;
			tb += s;
		}

		if (strcmp(type, "say")==0) {
			snprintf(tb, len, "%s: %s", whom, text);
		} else
		if (strcmp(type, "raw")==0) {
			snprintf(tb, len, "%s", text);
560
		} else
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
		if (strcmp(type, "emote")==0) {
			int plural = json_getint(j, "plural");
			switch (plural) {
				case 1:
					snprintf(tb, len, "%s's %s", whom, text);
					break;
				case 2:
					snprintf(tb, len, "%s' %s", whom, text);
					break;
				case 3:
					snprintf(tb, len, "%s'd %s", whom, text);
					break;
				case 4:
					snprintf(tb, len, "%s'll %s", whom, text);
					break;
				default:
					snprintf(tb, len, "%s %s", whom, text);
					break;
			}
580 581 582 583 584 585 586 587
		} else
		if (strcmp(type, "notsayto")==0) {
			const char *exclude = json_getstring(j, "exclude");
			if (exclude == NULL) exclude="Unknown";
			if (text[strlen(text)-1] == '?')
				snprintf(tb, len, "%s asks (-%s): %s", whom, exclude, text);
			else
				snprintf(tb, len, "%s says (-%s): %s", whom, exclude, text);
588 589 590 591
		} else {
			/* same as say for now */
			snprintf(tb, len, "%s: %s", whom, text);
		}
592
		force_text(msg, buff, whom);
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	} else
	if (msg->head.type == IPC_SAYTOUSER) {
		const char * type = json_getstring(j, "type");
		const char * text = json_getstring(j, "text");

		if (type == NULL || text == NULL) {
			printf("Invalid SAYTOUSER message from %s.\n", whom);
			json_decref(j);
			return;
		}

		char buff[MAXTEXTLENGTH];
		char * tb = buff;
		int len = MAXTEXTLENGTH;

		/* we have global on, prepend the channel number */
609
		if (cm_test(user, CM_GLOBAL)) {
610
			if (msg_posn == -1)
611
				snprintf(tb, len, "?:");
612
			else
613
				snprintf(tb, len, "%d:", msg_user.record.room);
614 615 616 617
			int s = strlen(tb);
			len -= s;
			tb += s;
		}
618

619 620 621 622 623 624 625 626
		if (strcmp(type, "whispers")==0) {
			snprintf(tb, len, "%s whispers: %s", whom, text);
		} else
		if (strcmp(type, "asks")==0) {
			snprintf(tb, len, "%s asks: %s", whom, text);
		} else  {
			snprintf(tb, len, "%s says: %s", whom, text);
		}
627
		force_text(msg, buff, whom);
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
	} else
	if (msg->head.type == IPC_SAYTOALL) {
		const char * text = json_getstring(j, "text");

		if (text == NULL) {
			printf("Invalid SAYTOALL message from %s.\n", whom);
			json_decref(j);
			return;
		}

		char buff[MAXTEXTLENGTH];
		char * tb = buff;
		int len = MAXTEXTLENGTH;

		/* we have global on, prepend the channel number */
643
		if (cm_test(user, CM_GLOBAL)) {
644 645 646 647 648
			snprintf(tb, len, "*:");
			int s = strlen(tb);
			len -= s;
			tb += s;
		}
649

650
		snprintf(tb, len, "%s shouts: %s", whom, text);
651
		force_text(msg, buff, whom);
652 653 654 655 656 657 658 659
	} else
	if (msg->head.type == IPC_EVENT) {
		const char * type = json_getstring(j, "type");
		const char * text = json_getstring(j, "text");
		const char * verbose = json_getstring(j, "verbose");
		const char * reason = json_getstring(j, "reason");

		if (verbose) force_text(msg, verbose, whom);
660 661 662 663

		/* user action messages have colour 15 */
		force_vtext(msg, whom, "\033%d%s", 15, text);

664 665
		if (reason) {
			if (strcasecmp(type, "mrod")==0 || strcasecmp(type, "zod")==0) {
666
				force_vtext(msg, whom, "Zebedee says \"%s\".", reason);
667
			} else {
668
				force_vtext(msg, whom, "%s gives the reason \"%s\".", whom, reason);
669 670
			}
		}
671 672 673 674 675 676 677 678 679 680 681 682 683 684
	} else
	if (msg->head.type == IPC_GAGLIST) {
		json_t *jgag;
		size_t i = 0;

		if (j== NULL || !json_is_array(j)) {
			printf("Invalid GAGLIST message from %s.\n", whom);
			json_decref(j);
			return;
		}
		gaglist_destroy();
		json_array_foreach(j, i, jgag) {
			gaglist_append(json_string_value(jgag));
		}
685 686
	} else {
		printf("Unknown message type %4.4s", (char *)&msg->head.type);
687 688
	}

689 690
	json_decref(j);

691
}
692

693
static void accept_pipe_cmd(ipc_message_t *msg, struct user *mesg_user)
694
{
695 696 697
	enum ipc_types state = msg->head.type;
	char *newbuff = msg->body;

698
	/*printf("\n<message type is %d>\n", state);*/
699 700 701 702 703
	switch (state) {
		case IPC_NEWMAIL:
			force_newmail();
			break;
		case IPC_STATUS:
704
			force_status(newbuff, mesg_user->record.name);
705 706
			break;
		case IPC_GROUPS:
Andrew Price's avatar
Andrew Price committed
707
			user->record.groups = folder_groups(newbuff, user->record.groups);
708 709
			break;
		case IPC_REALNAME:
Andrew Price's avatar
Andrew Price committed
710
			strcpy(user->record.realname, newbuff);
711 712
			break;
		case IPC_PASSWD:
Andrew Price's avatar
Andrew Price committed
713
			strcpy(user->record.passwd, newbuff);
714 715
			break;
		case IPC_CONTACT:
Andrew Price's avatar
Andrew Price committed
716
			strcpy(user->record.contact, newbuff);
717
			break;
718
		case IPC_DOING:
Andrew Price's avatar
Andrew Price committed
719 720
			snprintf(user->record.doing, DOINGSIZE,"%s", newbuff);
			user->record.dowhen = time(0);
721
			break;
722
		case IPC_SPECIAL:
Andrew Price's avatar
Andrew Price committed
723
			user->record.special = set_special(newbuff, user->record.special);
724 725
			break;
		case IPC_CHATPRIVS:
Andrew Price's avatar
Andrew Price committed
726
			user->record.chatprivs = cp_setbycode(user->record.chatprivs, newbuff);
727 728
			break;
		case IPC_CHATMODE:
729
			force_chatmode(newbuff, mesg_user->record.chatprivs, mesg_user->record.name);
730 731
			break;
		case IPC_GAG:
732
			force_gag(newbuff, mesg_user->record.chatprivs, mesg_user->record.name);
733
			break;
734 735 736
		case IPC_GAGLIST:
			display_content(msg);
			break;
737
		case IPC_PROTLEVEL:
738
			force_protlevel(newbuff, mesg_user->record.chatprivs, mesg_user->record.name);
739 740 741 742 743
			break;
		case IPC_PROTPOWER:
			force_protpower(newbuff);
			break;
		case IPC_USERNAME:
Andrew Price's avatar
Andrew Price committed
744 745
			snprintf(user->record.name, NAMESIZE+1, "%s", newbuff);
			printf(_("\nYour name has been changed to '%s'\n"), user->record.name);
746 747 748 749 750
			break;
		case IPC_LASTREAD:
			force_lastread(newbuff);
			break;
		case IPC_TIMEOUT:
Andrew Price's avatar
Andrew Price committed
751 752
			user->record.timeout = atoi(newbuff);
			reset_timeout(user->record.timeout);
753 754
			break;
		case IPC_TEXT:
755
			force_text(msg, newbuff, mesg_user->record.name);
756 757
			break;
		case IPC_SCRIPTIPC:
758
			force_ipc(newbuff, mesg_user->record.name);
759 760
			break;
		case IPC_SCRIPTRPC:
761
			force_rpc(newbuff, mesg_user->record.name);
762 763
			break;
		case IPC_CHECKONOFF:
764
			force_checkonoff(newbuff, mesg_user->record.name);
765 766
			break;
		case IPC_WIZ:
767
			force_wiz(msg, newbuff, mesg_user->record.name);
768 769
			break;
		case IPC_CHANNEL:
770
			force_channel(newbuff, mesg_user->record.name, mesg_user->record.chatprivs);
771 772
			break;
		case IPC_KICK:
773
			force_kick(newbuff, mesg_user->record.name, mesg_user->record.chatprivs);
774
			break;
775 776 777
		case IPC_UPTIME:
			display_uptime(msg);
			break;
778
		case IPC_SAYTOROOM:
779
		case IPC_SAYTOUSER:
780
		case IPC_SAYTOALL:
781
		case IPC_EVENT:
782 783
			display_content(msg);
			break;
784 785 786
		case IPC_TALKERROR:
			display_error(msg);
			break;
787 788 789
		case IPC_WHOLIST:
			update_wholist(msg);
			break;
790 791 792
		case IPC_ERROR:
			handle_ipc_error(msg);
			break;
793 794
		default:
			devel_msg("incoming_mesg", "unknown message type %d.\007", state);
795
	}
796

797
	ipcmsg_destroy(msg);
Andrew Price's avatar
Andrew Price committed
798
	update_user(user);
799 800
}

801 802 803 804 805
static void force_newmail(void)
{
	new_mail_waiting++;
}

806 807 808 809 810 811 812 813 814 815 816 817

static void force_vtext(ipc_message_t *msg, const char *from, const char *format, ...)
{
	va_list va;
	_autofree char * text = NULL;
	va_start(va, format);
	vasprintf(&text, format, va);
	va_end(va);

	force_text(msg, text, from);
}

818
static void force_text(ipc_message_t *msg, const char *text, const char *from)
819
{
820
	char tb[MAXTEXTLENGTH];
821 822 823 824
	struct mstack *mesg;

	mesg = malloc(sizeof(*mesg));
	mesg->flags = MST_EVENT|MST_BEEP;
825

826
	tb[0]=0;
827
	if (s_timestamp(user))
828 829 830
	{
		time_t t;
		struct tm *tt;
831

832
		t= msg->head.when;
833
		tt=localtime(&t);
834
		strftime(tb, MAXTEXTLENGTH,"%H:%M ", tt);
835
	}
836
	if (cm_test(user, CM_SPY))
837
	{
838 839
		strncat(tb, from, MAXTEXTLENGTH - strlen(tb) - 1);
		strncat(tb, "> ", MAXTEXTLENGTH - strlen(tb) - 1);
840 841
	}
	mesg->preamble = strlen(tb);
842
	if (cm_test(user, CM_GLOBAL))
843 844 845 846 847 848 849
	{
		char *i = strchr(text, ':');
		if (i != NULL)
		{
			mesg->preamble += (i-text+1);
		}
	}
850
	strncat(tb, text, MAXTEXTLENGTH - strlen(tb) - 1);
851 852 853
	mesg->text = strdup(tb);
	mesg->from = strdup(from);

854
	/*printf("\n<Received message from %s: \'%s\'>\n", from, text);*/
855 856 857
	InsertMesg(mesg);
}

858
static void force_wiz(ipc_message_t *msg, char *newbuff, char *from)
859 860 861 862
{
	char tb[MAXTEXTLENGTH];
	tb[0]=0;

863
	if (s_timestamp(user))
864 865 866 867
	{
		time_t t;
		struct tm *tt;

868
		t = msg->head.when;
869 870 871
		tt=localtime(&t);
		strftime(tb, MAXTEXTLENGTH,"%H:%M ", tt);
	}
872
	if (cm_test(user, CM_SPY))
873 874 875 876 877 878 879 880 881
	{
		strncat(tb, from, MAXTEXTLENGTH - strlen(tb) - 1);
		strncat(tb, "> ", MAXTEXTLENGTH - strlen(tb) - 1);
	}
	strncat(tb, newbuff, MAXTEXTLENGTH - strlen(tb) - 1);

	StackMesg(tb, from, 0);
}

882 883
static void force_checkonoff(char *text, char *from)
{
884
	if (cp_test(user, CP_SCRIPT))
885
	{
886
		StackEvent(text, from, EST_CHECKONOFF);
887 888 889
	}
}

890 891
static void force_ipc(char *text, char *from)
{
892
	if (cp_test(user, CP_SCRIPT))
893
	{
894
		StackEvent(text, from, EST_IPC);
895 896 897
	}
}

Chris Fry's avatar
Chris Fry committed
898 899
static void force_rpc(char *text, char *from)
{
900
	if (cp_test(user, CP_SCRIPT))
Chris Fry's avatar
Chris Fry committed
901
	{
902
		StackEvent(text, from, EST_RPC);
Chris Fry's avatar
Chris Fry committed
903 904 905
	}
}

906
static void force_status(char *newbuff, char *from)
907
{
Andrew Price's avatar
Andrew Price committed
908
	user->record.status = user_stats(newbuff, user->record.status);
909
	/* we have received a ban */
910
	if (u_ban(user))
911
	{
912
		printf(_("\n\n--> You appear to have been banned. Goodbye... <--\r\n"));
913
		close_down(4, from, NULL);
914 915
	}
	/* we have received a +D status change */
916
	if (u_del(user))
917
	{
918
		printf(_("\n\n--> You appear to have been DELETED. Goodbye... <--\r\n"));
919
		close_down(6, from, NULL);
920 921 922
	}
}

923
static void force_chatmode(char *newbuff, unsigned long theirprivs, const char *from)
924 925
{
	unsigned long	mm;
Andrew Price's avatar
Andrew Price committed
926
	int		ourapl = (user->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
927 928 929
	int		theirapl = (theirprivs & CP_PROTMASK) >> CP_PROTSHIFT;
	int		oldchat;

930 931
	if (!(theirprivs & CP_PROTECT)) theirapl = 0;
	oldchat = cm_test(user, CM_ONCHAT);
932

Andrew Price's avatar
Andrew Price committed
933 934
	mm=cm_setbycode(user->record.chatmode, newbuff);
	user->record.chatmode=chatmode_describe(user->record.chatmode, mm, ourapl, theirapl, from);
935

936
	if (!cm_test(user, CM_ONCHAT) && oldchat)
937 938
	{
		/* announce leaving talker */
939
		broadcast_onoffcode(0, 2, from, NULL);
940
	}
941
	else if (cm_test(user, CM_ONCHAT) && !oldchat)
942 943
	{
		/* announce joining the talker */
944
		broadcast_onoffcode(1, 2, from, NULL);
945 946
	}

947
	disable_rl(1);
948 949
}

950
static void force_gag(char *newbuff, unsigned long theirprivs, const char *from)
951
{
Andrew Price's avatar
Andrew Price committed
952
	int ourapl = (user->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
953
	int theirapl = (theirprivs & CP_PROTMASK) >> CP_PROTSHIFT;
954
	if (!(theirprivs & CP_PROTECT)) theirapl = 0;
955

Andrew Price's avatar
Andrew Price committed
956
	unsigned long newcm = user->record.chatmode & ~CM_GAGMASK;
957
	if (newbuff[0]=='+')
958 959
		newcm |= atoi(&newbuff[1]) << CM_GAGSHIFT;

Andrew Price's avatar
Andrew Price committed
960
	user->record.chatmode=chatmode_describe(user->record.chatmode, newcm, ourapl, theirapl, from);
961

962
	disable_rl(1);
963 964
}

965
static void force_protlevel(char *newbuff, unsigned long theirprivs, const char* from)
966
{
967 968
	unsigned long cm, pbits;
	int level;
Andrew Price's avatar
Andrew Price committed
969
	int ourapl = (user->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
970
	int theirapl = (theirprivs & CP_PROTMASK) >> CP_PROTSHIFT;
971
	if (!(theirprivs & CP_PROTECT)) theirapl = 0;
972 973 974 975 976

	level = atoi(newbuff);
	/* `pbits' contains both the temporary protect bit and permanent
	 * protection level.  if level==-1 then give temp protection only
	 */
977
	pbits = (level>=0? level: 0) << CM_PROTSHIFT;
978
	if (level != 0) pbits |= CM_PROTECTED;
Andrew Price's avatar
Andrew Price committed
979
	cm=user->record.chatmode;
980
	cm ^= pbits; cm &= ~(CM_PROTMASK|CM_PROTECTED); cm ^= pbits;
981

Andrew Price's avatar
Andrew Price committed
982
	user->record.chatmode = chatmode_describe(user->record.chatmode, cm, ourapl, theirapl, from);
983 984 985 986
}

static void force_protpower(char *newbuff)
{
987
	unsigned long cp, pbits;
988

989
	pbits = atoi(newbuff) << CP_PROTSHIFT;
Andrew Price's avatar
Andrew Price committed
990
	cp=user->record.chatprivs;
991

992
	cp ^= pbits; cp &= ~CP_PROTMASK; cp ^= pbits;
993

Andrew Price's avatar
Andrew Price committed
994
	user->record.chatprivs = cp;
995 996 997
}

static void force_channel(char *newbuff, char *from, unsigned long theirprivs)
998 999 1000
{
	int newroom=atoi(&newbuff[1]);
	char mode = newbuff[0];
1001
	char text[MAXTEXTLENGTH];
1002
	int theirapl = (theirprivs & CP_PROTMASK) >> CP_PROTSHIFT;
Andrew Price's avatar
Andrew Price committed
1003
	int prot = (user->record.chatmode & CM_PROTMASK) >> CM_PROTSHIFT;
1004 1005
	if (!(theirprivs & CP_PROTECT)) theirapl = 0;
	if (prot == 0 && cm_test(user, CM_PROTECTED))
1006
		prot = 1;
1007

1008
	if (!cm_test(user, CM_ONCHAT))
1009
	{
1010 1011
		if ((mode != 's') && (theirapl<prot))
		{
1012
			snprintf(text,MAXTEXTLENGTH-1,"\03315%s just tried to summon you onto the talker into room %d.",from,newroom);
1013 1014 1015
			display_message(text, 1, 1);
		}else
		{
1016
			snprintf(text,MAXTEXTLENGTH-1,"\03315You have been summoned into talker room %d by %s.",newroom,from);
1017 1018
			display_message(text, 1, 1);
			set_talk_rights();
Andrew Price's avatar
Andrew Price committed
1019
			user->record.room = newroom;
1020

Andrew Price's avatar
Andrew Price committed
1021
			snprintf(text,MAXTEXTLENGTH-1,"\03310%s has just been summoned into talker room %d by %s",user->record.name,newroom,from);
1022
			talk_send_rawbcast(text);
1023
			user->record.chatmode = cm_set(user, CM_ONCHAT);
1024

1025 1026 1027
			RoomDestroy(&user->room);
			RoomInit(&user->room);
			LoadRoom(&user->room, newroom);
1028 1029

			/* force update of user information _before_ scripts are run */
Andrew Price's avatar
Andrew Price committed
1030
			update_user(user);
1031 1032 1033

			/* run common talker entrance code with logon type set to 'summon' */
			enter_talker(2);
1034 1035

			/* give an entrance broadcast */
1036
			broadcast_onoffcode(1, 1, from, NULL);
1037

1038
			enter_room(newroom);
1039
		}
1040 1041
	}else
	{
1042
		if ((mode != 's') && (theirapl<prot))
1043
		{
1044 1045 1046 1047
			/*
			snprintf(text,MAXTEXTLENGTH-1,"%s just tried to summon you to room %d.",from,newroom);
			display_message(text, 1, 1);
			*/
1048 1049 1050
		}else
		{
			int o;
Andrew Price's avatar
Andrew Price committed
1051
			snprintf(text,MAXTEXTLENGTH-1,"\03312%s has just arrived in room %d",user->record.name,newroom);
1052
			talk_send_raw(text,newroom);
Andrew Price's avatar
Andrew Price committed
1053 1054 1055
			o = user->record.room;
			user->record.room = (unsigned short)newroom;
			snprintf(text,MAXTEXTLENGTH-1,"\03313%s has left to room %d", user->record.name, newroom);
1056
			talk_send_raw(text,o);
1057
			snprintf(text,MAXTEXTLENGTH-1,"\03315You have been summoned to room %d by %s.",newroom,from);
1058
			display_message(text, 1, 1);
1059

1060 1061 1062
			RoomDestroy(&user->room);
			RoomInit(&user->room);
			LoadRoom(&user->room, newroom);
1063
			enter_room(newroom);
1064 1065 1066
		}
	}
	disable_rl(1);
1067

1068 1069
}

1070
static void force_kick(char *newbuff, char *from, unsigned long theirprivs)
1071
{
1072 1073
	char	*msg = NULL;
	char	type;
1074

1075
	type = *newbuff;
1076
	if (newbuff[1] == 'r') msg = &newbuff[2];
1077

1078
	if (type=='z')
1079
	{
1080
		zod(from, msg);
1081
	}else
1082
	if (type=='m')
1083
	{
1084
		mrod(from, msg);
1085
	} else
1086
	if (type=='k')
1087
	{
1088
		zod(from, msg);
1089
	}else
1090
	if (type=='r')
1091
	{
1092
		mrod(from, msg);
1093 1094 1095
	}
}

1096
static void zod(char *from, char *msg)
1097
{
1098 1099
	char text[MAXTEXTLENGTH];

1100
	/* remove from talker */
1101
	user->record.chatmode = cm_clear(user, CM_ONCHAT);
1102 1103

	/* force update of user */
Andrew Price's avatar
Andrew Price committed
1104
	update_user(user);
1105

1106
	/* announce leaving talker via zod */
1107
	broadcast_onoffcode(0, 1, from, msg);
1108

1109
	/* put standard message to screen */
1110 1111
	snprintf(text, MAXTEXTLENGTH-1, _("\nBoing, Zebedee arrived.  \"%s\033--\", said Zebedee\n"), (msg!=NULL)?msg:_("Time for bed"));
	display_message(text, 1, 1);
1112
	printf(_("%s just sent the Zebedee of Death to you.\n"),from);
1113 1114
	fflush(stdout);

1115
	/* broadcast leaving message if not quiet */
Andrew Price's avatar
Andrew Price committed
1116
	if (!quietmode) broadcast(4|0x100, "\03311%s has just left the talker", user->record.name);
1117

1118
	/* set 'off talker' permissions for commands */
1119 1120 1121 1122
	set_rights();
	disable_rl(1);
}

1123
static void mrod(char *from, char *msg)
1124
{
1125
	char mrod_message[MAXTEXTLENGTH];
1126
	/* make sure we have left talker */
1127
	/*user->chatmode=cm_flags(user->chatmode, CM_ONCHAT, CM_MODE_CLEAR);*/
Andrew Price's avatar
Andrew Price committed
1128
	update_user(user);
1129 1130

	printf("\n");
1131 1132 1133 1134 1135 1136 1137
	printf(_("Boing, Zebedee's arrived.  \"Look up!\", says Zebedee\n"));
	printf(_("You look up; a large object is falling towards you very fast,\n"));
	printf(_("very very fast.  It looks like a Magic Roundabout!\n"));
	printf(_("\"I wouldn't stand there if I was you\", says Zebedee\n"));
	printf(_("Boing, Zebedee's left you standing all alone\n"));
	printf(_("WWWHHHEEEEEEEKKKKEEEERRRRRUUUUUNNNNNCCCCCHHHHHH\7\7\7\7\7\n"));
	printf(_("%s has just dropped the Magic Roundabout of Death on you.\n"),from);
1138
	if (msg!=NULL)
1139 1140 1141 1142
	{
		snprintf(mrod_message, MAXTEXTLENGTH-1, _("\"%s\033--\" says Zebedee\n"), msg);
		display_message(mrod_message, 1, 1);
	}
1143 1144
	fflush(stdout);

1145
	fix_terminal();
1146

1147 1148
	mrod_user = malloc(sizeof(char) * (strlen(from) + 1));
	strcpy(mrod_user, from);