Skip to content
Snippets Groups Projects
term.c 81.8 KiB
Newer Older
					FILE* fp = fopen(fpick.selected[0], "wb");
					if(fp == NULL) {
						char err[256];
						sprintf(err, "Error %u opening file '%s'", errno, fpick.selected[0]);
						uifc.msg(err);
					} else {
						char msg[256];
						uifc.pop("Writing to file");
						fwrite(cap, sizeof(uint8_t), cterm->width * cterm->height * 2, fp);
						if(i > 2) {
							time_t t = time(NULL);
							struct tm* tm;
							struct sauce sauce;

							memset(&sauce, 0, sizeof(sauce));
							memcpy(sauce.id, SAUCE_ID, sizeof(sauce.id));
							memcpy(sauce.ver, SAUCE_VERSION, sizeof(sauce.ver));
							memset(sauce.title, ' ', sizeof(sauce.title));
							memset(sauce.author, ' ', sizeof(sauce.author));
							memset(sauce.group, ' ', sizeof(sauce.group));
							if(bbs != NULL) {
								memcpy(sauce.title, bbs->name, MIN(strlen(bbs->name), sizeof(sauce.title)));
								memcpy(sauce.author, bbs->user, MIN(strlen(bbs->user), sizeof(sauce.author)));
							}
							if((tm=localtime(&t)) != NULL)	// The null-terminator overwrites the first byte of filesize
								sprintf(sauce.date, "%04u%02u%02u"
									,1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday);
							sauce.filesize = LE_INT32(ftell(fp));	// LE
							sauce.datatype = sauce_datatype_bin;
							sauce.filetype = cterm->width / 2;
							if(ciolib_getvideoflags() & (CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK))
								sauce.tflags |= sauce_ansiflag_nonblink;

							fputc(SAUCE_SEPARATOR, fp);
							/* No comment block (no comments) */
							fwrite(&sauce.id, sizeof(sauce.id), 1, fp);
							fwrite(&sauce.ver, sizeof(sauce.ver), 1, fp);
							fwrite(&sauce.title, sizeof(sauce.title), 1, fp);
							fwrite(&sauce.author, sizeof(sauce.author), 1, fp);
							fwrite(&sauce.group, sizeof(sauce.group), 1, fp);
							fwrite(&sauce.date, sizeof(sauce.date), 1, fp);
							fwrite(&sauce.filesize, sizeof(sauce.filesize), 1, fp);
							fwrite(&sauce.datatype, sizeof(sauce.datatype), 1, fp);
							fwrite(&sauce.filetype, sizeof(sauce.filetype), 1, fp);
							fwrite(&sauce.tinfo1, sizeof(sauce.tinfo1), 1, fp);
							fwrite(&sauce.tinfo2, sizeof(sauce.tinfo2), 1, fp);
							fwrite(&sauce.tinfo3, sizeof(sauce.tinfo3), 1, fp);
							fwrite(&sauce.tinfo4, sizeof(sauce.tinfo4), 1, fp);
							fwrite(&sauce.comments, sizeof(sauce.comments), 1, fp);
							fwrite(&sauce.tflags, sizeof(sauce.tflags), 1, fp);
							fwrite(&sauce.tinfos, sizeof(sauce.tinfos), 1, fp);
						}
						fclose(fp);
						uifc.pop(NULL);
						sprintf(msg, "Screen saved to '%s'", getfname(fpick.selected[0]));
						uifc.msg(msg);
					}
				} else
					cterm_openlog(cterm, fpick.selected[0], i?CTERM_LOG_RAW:CTERM_LOG_ASCII);
			}
			filepick_free(&fpick);
		}
		if(cterm->log & CTERM_LOG_PAUSED) {
			char *opts[3]={
							 "Unpause"
							,"Close"
						  };
			i=0;
			uifc.helpbuf="`Capture Control`\n\n"
						"~ Unpause ~ Continues logging\n"
						"~ Close ~   Closes the log\n\n";
			if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,"Capture Control",opts)!=-1) {
				switch(i) {
						cterm->log=cterm->log & CTERM_LOG_MASK;
						break;
				}
			}
		}
		else {
			char *opts[3]={
							 "Pause"
							,"Close"
						  };
			i=0;
			uifc.helpbuf="`Capture Control`\n\n"
						"~ Pause ~ Suspends logging\n"
						"~ Close ~ Closes the log\n\n";
			if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,"Capture Control",opts)!=-1) {
				switch(i) {
rswindell's avatar
rswindell committed
						cterm->log |= CTERM_LOG_PAUSED;
	restorescreen(savscrn);
	freescreen(savscrn);
#define OUTBUF_SIZE	2048

#define WRITE_OUTBUF()	\
	if(outbuf_size > 0) { \
		cterm_write(cterm, outbuf, outbuf_size, (char *)ansi_replybuf, sizeof(ansi_replybuf), &speed); \
		if(ansi_replybuf[0]) \
			conn_send(ansi_replybuf, strlen((char *)ansi_replybuf), 0); \
static int get_cache_fn_base(struct bbslist *bbs, char *fn, size_t fnsz)
{
	get_syncterm_filename(fn, fnsz, SYNCTERM_PATH_CACHE, FALSE);
	backslash(fn);
	strcat(fn, bbs->name);
	backslash(fn);
	if (!isdir(fn))
deuce's avatar
deuce committed
		mkpath(fn);
	if (!isdir(fn))
		return 0;
	return 1;
}

static int clean_path(char *fn, size_t fnsz)
{
	char *fp;

	fp = _fullpath(NULL, fn, fnsz);
	if (fp == NULL || strcmp(fp, fn)) {
		FREE_AND_NULL(fp);
		return 0;
	}
	FREE_AND_NULL(fp);
	return 1;
}

static void apc_handler(char *strbuf, size_t slen, void *apcd)
{
	char fn[MAX_PATH+1];
	char fn_root[MAX_PATH+1];
	FILE *f;
	int rc;
	size_t sz;
	char *p;
	char *buf;
	struct bbslist *bbs = apcd;
	glob_t gl;
	int i;
	MD5	ctx;
	BYTE	digest[MD5_DIGEST_SIZE];
	unsigned long slot;

	if(ansi_replybuf[0])
		conn_send(ansi_replybuf, strlen((char *)ansi_replybuf), 0);
	if (get_cache_fn_base(bbs, fn_root, sizeof(fn_root)) == 0)
		return;
	strcpy(fn, fn_root);

	if (strncmp(strbuf, "SyncTERM:C;S;", 13)==0) {
		// Request to save b64 encoded data into the cache directory.
		p = strchr(strbuf+13, ';');
		if (p == NULL)
			return;
		strncat(fn, strbuf+13, p-strbuf-13);
		if (!clean_path(fn, sizeof(fn)))
			return;
		p++;
		sz = (slen - (p-strbuf)) * 3 / 4 + 1;
		buf = malloc(sz);
		if (!buf)
			return;
		rc = b64_decode(buf, sz, p, slen);
		if (rc < 0) {
			free(buf);
			return;
		}
		p = strrchr(fn, '/');
		if (p) {
			*p = 0;
			mkpath(fn);
			*p = '/';
		}
		f = fopen(fn, "wb");
		if (f == NULL) {
			free(buf);
			return;
		}
		fwrite(buf, rc, 1, f);
		free(buf);
		fclose(f);
	}
	else if (strncmp(strbuf, "SyncTERM:C;L", 12) == 0) {
		// Cache list
		if (strbuf[12] != 0 && strbuf[12] != ';')
			return;
		if (!clean_path(fn, sizeof(fn))) {
			conn_send("\x1b_SyncTERM:C;L\n\x1b\\", 17, 0);
			return;
		}
		if (!isdir(fn)) {
			conn_send("\x1b_SyncTERM:C;L\n\x1b\\", 17, 0);
			return;
		}
		if (slen == 12)
			p = "*";
		else
			p = strbuf+13;
		strcat(fn, p);
		conn_send("\x1b_SyncTERM:C;L\n", 15, 0);
		rc = glob(fn, GLOB_MARK, NULL, &gl);
		if (rc != 0) {
			conn_send("\x1b\\", 2, 0);
			return;
		}
		buf = malloc(1024*32);
		if (buf == NULL)
			return;
		for (i=0; i<gl.gl_pathc; i++) {
			/* Skip . and .. along with any fuckery */
			if (!clean_path(gl.gl_pathv[i], MAX_PATH))
				continue;
			p = getfname(gl.gl_pathv[i]);
			conn_send(p, strlen(p), 0);
			conn_send("\t", 1, 0);
			f = fopen(gl.gl_pathv[i], "rb");
			if (f) {
				MD5_open(&ctx);
				while (!feof(f)) {
					rc = fread(buf, 1, 1024*32, f);
					if (rc > 0)
						MD5_calc(digest, buf, rc);
				}
				fclose(f);
				MD5_hex((BYTE *)buf, digest);
				conn_send(buf, strlen(buf), 0);
			}
			conn_send("\n", 1, 0);
		}
		free(buf);
		conn_send("\x1b\\", 2, 0);
		globfree(&gl);
	}
	else if (strncmp(strbuf, "SyncTERM:C;SetFont;", 19) == 0) {
		slot = strtoul(strbuf+19, &p, 10);
		if (slot < CONIO_FIRST_FREE_FONT)
			return;
		if (slot > 255)
			return;
		if (*p != ';')
			return;
		p++;
		strcat(fn, p);
		if (!clean_path(fn, sizeof(fn)))
			return;
		if (!fexist(fn))
			return;
		sz = flength(fn);
		f = fopen(fn, "rb");
		if (f) {
			buf = malloc(sz);
			if (buf == NULL) {
				fclose(f);
				return;
			}
			if (fread(buf, sz, 1, f) != 1) {
				fclose(f);
				free(buf);
				return;
			}
			switch(sz) {
				case 4096:
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].eight_by_sixteen);
					conio_fontdata[cterm->font_slot].eight_by_sixteen=buf;
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].desc);
					conio_fontdata[cterm->font_slot].desc=strdup("Cached Font");
					break;
				case 3584:
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].eight_by_fourteen);
					conio_fontdata[cterm->font_slot].eight_by_fourteen=buf;
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].desc);
					conio_fontdata[cterm->font_slot].desc=strdup("Cached Font");
					break;
				case 2048:
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].eight_by_eight);
					conio_fontdata[cterm->font_slot].eight_by_eight=buf;
					FREE_AND_NULL(conio_fontdata[cterm->font_slot].desc);
					conio_fontdata[cterm->font_slot].desc=strdup("Cached Font");
					break;
				default:
					free(buf);
			}
			fclose(f);
		}
	}
}

void mouse_state_change(int type, int action, void *pms)
	struct mouse_state *ms = (struct mouse_state *)pms;

	if (ms->mode == MM_RIP)
		return;
		if (type == ms->mode) {
			ms->mode = MM_OFF;
		}
		if (type == MS_SGR_SET) {
			ms->flags &= ~MS_FLAGS_SGR;
		}
		switch (type) {
			case MM_X10:
			case MM_NORMAL_TRACKING:
			case MM_BUTTON_EVENT_TRACKING:
			case MM_ANY_EVENT_TRACKING:
				ms->mode = type;
				setup_mouse_events(ms);
				break;
			case MS_SGR_SET:
				ms->flags |= MS_FLAGS_SGR;
int mouse_state_query(int type, void *pms)
{
	struct mouse_state *ms = (struct mouse_state *)pms;

	if (type == MS_SGR_SET)
		return ms->flags & MS_FLAGS_SGR;
	return type == ms->mode;
}

/* Win32 doesn't have ffs()... just use this everywhere. */
static int
my_ffs(int mask)
{
	int bit;

	if (mask == 0)
		return(0);
	for (bit = 1; !(mask & 1); bit++)
		mask = (unsigned int)mask >> 1;
	return (bit);
}

static int fill_mevent(char *buf, size_t bufsz, struct mouse_event *me, struct mouse_state *ms)
	int x = me->startx - cterm->x + 1;
	int y = me->starty - cterm->y + 1;
	int bit;
	int ret;
	bool release;

	// TODO: Get modifier keys too...
	if (me->event == CIOLIB_MOUSE_MOVE) {
		if ((me->kbsm & me->bstate) == 0) {
			if (ms->mode == MM_BUTTON_EVENT_TRACKING)
				return 0;
		}
		bit = my_ffs(me->kbsm & me->bstate);
		button = bit - 1;
		release = false;
	}
	else {
		button = CIOLIB_BUTTON_NUMBER(me->event);
		release =  (me->event == CIOLIB_BUTTON_RELEASE(button));
		button--;
	}
	if (button >= 7)
		button += 121;
	else if (button >= 3) {
		button += 61;
	}
	if (me->event == CIOLIB_MOUSE_MOVE)
		button += 32;
	if ((ms->flags & MS_FLAGS_SGR) == 0) {
		if (bufsz < 6)
			return 0;
		if (release)
			button = 3;
		x--;
		y--;
		if (x < 0)
			x = 0;
		if (x > 222)
			x = 222;
		if (y < 0)
			y = 0;
		if (y > 222)
			y = 222;
		buf[0] = '\x1b';
		buf[1] = '[';
		buf[2] = 'M';
		buf[3] = ' '+button;
		buf[4] = '!'+x;
		buf[5] = '!'+y;
		return 6;
	}
	else {
		ret = snprintf(buf, bufsz, "\x1b[<%d;%d;%d%c", button, x, y, release ? 'm' : 'M');
		if (ret > bufsz)
			return 0;
		return ret;
	}
void
do_paste(void)
{
	uint8_t *p;
	uint8_t *p2;
	int oldfont;

	p=(unsigned char *)getcliptext();
	if(p!=NULL) {
		p2 = p;
		oldfont = getfont(1);
		setfont(cterm->altfont[0], FALSE, 1);
		p = (unsigned char *)utf8_to_cp(getcodepage(), p, '\x00', strlen((char *)p), NULL);
		setfont(oldfont, FALSE, 1);
		free(p2);
		if (p != NULL) {
			for(p2=p; *p2; p2++) {
				if(*p2=='\n') {
					/* If previous char was not \r, send a \r */
					if(p2==p || *(p2-1)!='\r')
						conn_send("\r",1,0);
				}
				else
					conn_send(p2,1,0);
			}
			free(p);
		}
	}
}

BOOL doterm(struct bbslist *bbs)
	unsigned char outbuf[OUTBUF_SIZE];
	size_t outbuf_size=0;
	BYTE zrqinit[] = { ZDLE, ZHEX, '0', '0', 0 };	/* for Zmodem auto-downloads */
	BYTE zrinit[] = { ZDLE, ZHEX, '0', '1', 0 };	/* for Zmodem auto-uploads */
deuce's avatar
deuce committed
	BYTE zrqbuf[sizeof(zrqinit)];
deuce's avatar
deuce committed
	long double nextchar=0;
	long double lastchar=0;
	long double thischar=0;
deuce's avatar
deuce committed
	int	oldmc;
	int	updated=FALSE;
deuce's avatar
deuce committed
	BOOL	sleep;
	struct text_info txtinfo;
#ifndef WITHOUT_OOII
	BYTE ooii_buf[256];
deuce's avatar
deuce committed
	BYTE ooii_init1[] = "\xdb\b \xdb\b \xdb\b[\xdb\b[\xdb\b \xdb\bM\xdb\ba\xdb\bi\xdb\bn\xdb\bt\xdb\be\xdb\bn\xdb\ba\xdb\bn\xdb\bc\xdb\be\xdb\b \xdb\bC\xdb\bo\xdb\bm\xdb\bp\xdb\bl\xdb\be\xdb\bt\xdb\be\xdb\b \xdb\b]\xdb\b]\xdb\b \b\r\n\r\n\r\n\x1b[0;0;36mDo you have the Overkill Ansiterm installed? (y/N)  \xe9 ";	/* for OOII auto-enable */
	BYTE ooii_init2[] = "\xdb\b \xdb\b \xdb\b[\xdb\b[\xdb\b \xdb\bM\xdb\ba\xdb\bi\xdb\bn\xdb\bt\xdb\be\xdb\bn\xdb\ba\xdb\bn\xdb\bc\xdb\be\xdb\b \xdb\bC\xdb\bo\xdb\bm\xdb\bp\xdb\bl\xdb\be\xdb\bt\xdb\be\xdb\b \xdb\b]\xdb\b]\xdb\b \b\r\n\r\n\x1b[0m\x1b[2J\r\n\r\n\x1b[0;1;30mHX Force retinal scan in progress ... \x1b[0;0;30m";	/* for OOII auto-enable */
deuce's avatar
deuce committed
	int ooii_mode=0;
	recv_byte_buffer_len=recv_byte_buffer_pos=0;
	struct mouse_state ms = {0};
	gettextinfo(&txtinfo);
	if(bbs->conn_type == CONN_TYPE_SERIAL)
deuce's avatar
deuce committed
		speed = 0;
	else
		speed = bbs->bpsrate;
	log_level = bbs->xfer_loglevel;
	conn_api.log_level = bbs->telnet_loglevel;
	vc=realloc(scrollback_buf, term.width*sizeof(*vc)*settings.backlines);
	if(vc != NULL) {
		scrollback_buf=vc;
		memset(scrollback_buf,0,term.width*sizeof(*vc)*settings.backlines);
	}
	else
		FREE_AND_NULL(scrollback_buf);
	scrollback_lines=0;
	scrollback_mode=txtinfo.currmode;
	cterm=cterm_init(term.height,term.width,term.x-1,term.y-1,settings.backlines,term.width,scrollback_buf, get_emulation(bbs));
	cterm->apc_handler = apc_handler;
	cterm->apc_handler_data = bbs;
	cterm->mouse_state_change = mouse_state_change;
	cterm->mouse_state_change_cbdata = &ms;
	cterm->mouse_state_query = mouse_state_query;
	cterm->mouse_state_query_cbdata = &ms;
	scrollback_cols=term.width;
	cterm->music_enable=bbs->music;
	zrqbuf[0]=0;
#ifndef WITHOUT_OOII
	ooii_buf[0]=0;
#endif
deuce's avatar
deuce committed
	oldmc=hold_update;
	showmouse();
	init_rip(bbs->rip);
	if (bbs->rip)
		ms.mode = MM_RIP;
	setup_mouse_events(&ms);
deuce's avatar
deuce committed
		hold_update=TRUE;
		if(!term.nostatus)
			update_status(bbs, (bbs->conn_type == CONN_TYPE_SERIAL)?bbs->bpsrate:speed, ooii_mode);
		for(remain=count_data_waiting() /* Hack for connection check */ + (!is_connected(NULL)); remain; remain--) {
deuce's avatar
deuce committed
			if(speed)
				thischar=xp_timer();

			if((!speed) || thischar < lastchar /* Wrapped */ || thischar >= nextchar) {
				/* Get remote input */
				inch=recv_byte(NULL, 0);

				switch(inch) {
					case -1:
						if(!is_connected(NULL)) {
							hold_update=oldmc;
							if (!bbs->hidepopups) {
								uifcmsg("Disconnected","`Disconnected`\n\nRemote host dropped connection");
							}
							cterm_clearscreen(cterm, cterm->attr);	/* Clear screen into scrollback */
							scrollback_lines=cterm->backpos;
							cterm_end(cterm);
							conn_close();
							hidemouse();
							return(FALSE);
						}
						break;
					default:
						if(speed) {
							lastchar = xp_timer();
							nextchar = lastchar + 1/(long double)(speed/10);
						}
						switch (speedwatch) {
							case 0:
								if (inch == '\x1b')
									speedwatch = 1;
								break;
							case 1:
								if (inch == '[')
									speedwatch = 2;
								else
									speedwatch = 0;
								break;
							case 2:
								if (inch == '0' || inch == '1')
									speedwatch = 3;
								else
									speedwatch = 0;
								break;
							case 3:
								if (inch == ';')
									speedwatch = 4;
								else
									speedwatch = 0;
								break;
							case 4:
								if (inch >= '0' && inch <= '9')
									break;
								if (inch == '*')
									speedwatch = 5;
								else
									speedwatch = 0;
								break;
							case 5:
								if (inch == 'r')
									remain = 1;
								speedwatch = 0;
								break;
						}
deuce's avatar
deuce committed
						j=strlen((char *)zrqbuf);
deuce's avatar
deuce committed
						if(inch == zrqinit[j] || inch == zrinit[j]) {
							zrqbuf[j]=inch;
							zrqbuf[++j]=0;
							if(j==sizeof(zrqinit)-1) {	/* Have full sequence (Assumes zrinit and zrqinit are same length */
								suspend_rip(true);
deuce's avatar
deuce committed
								if(!strcmp((char *)zrqbuf, (char *)zrqinit))
deuce's avatar
deuce committed
									zmodem_download(bbs);
								else
									begin_upload(bbs, TRUE, inch);
								suspend_rip(false);
deuce's avatar
deuce committed
								zrqbuf[0]=0;
								remain=1;
deuce's avatar
deuce committed
						else
							zrqbuf[0]=0;
#ifndef WITHOUT_OOII
						if(ooii_mode) {
							if(ooii_buf[0]==0) {
								if(inch == 0xab) {
									ooii_buf[0]=inch;
									ooii_buf[1]=0;
									continue;
								}
							}
							else { /* Already have the start of the sequence */
deuce's avatar
deuce committed
								j=strlen((char *)ooii_buf);
								if(j+1 >= sizeof(ooii_buf))
									j--;
								ooii_buf[j++]=inch;
								ooii_buf[j]=0;
								if(inch == '|') {
									if(handle_ooii_code(ooii_buf, &ooii_mode, (unsigned char *)ansi_replybuf, sizeof(ansi_replybuf))) {
deuce's avatar
deuce committed
										ooii_mode=0;
									if(ansi_replybuf[0])
										conn_send(ansi_replybuf,strlen((char *)ansi_replybuf),0);
deuce's avatar
deuce committed
							j=strlen((char *)ooii_buf);
deuce's avatar
deuce committed
							if(inch==ooii_init1[j]) {
								ooii_buf[j++]=inch;
								ooii_buf[j]=0;
								if(ooii_init1[j]==0) {
deuce's avatar
deuce committed
									if(strcmp((char *)ooii_buf, (char *)ooii_init1)==0) {
deuce's avatar
deuce committed
										ooii_mode=1;
deuce's avatar
deuce committed
									ooii_buf[0]=0;
								}
							}
							else if(inch==ooii_init2[j]) {
								ooii_buf[j++]=inch;
								ooii_buf[j]=0;
deuce's avatar
deuce committed
								if(ooii_init2[j]==0) {
deuce's avatar
deuce committed
									if(strcmp((char *)ooii_buf, (char *)ooii_init2)==0) {
deuce's avatar
deuce committed
										ooii_mode=2;
deuce's avatar
deuce committed
									ooii_buf[0]=0;
								}
deuce's avatar
deuce committed
							else
								ooii_buf[0]=0;
						if(outbuf_size >= sizeof(outbuf))
							WRITE_OUTBUF();
						outbuf[outbuf_size++]=inch;
		if(updated) {
deuce's avatar
deuce committed
			hold_update=FALSE;
deuce's avatar
deuce committed
			gotoxy(wherex(), wherey());
deuce's avatar
deuce committed
		}
deuce's avatar
deuce committed
		hold_update=oldmc;
		while(quitting || rip_kbhit()) {
deuce's avatar
deuce committed
			struct mouse_event mevent;
deuce's avatar
deuce committed
			updated=TRUE;
			gotoxy(wherex(), wherey());
				key = rip_getch();
				if (key == -1)
					continue;
				if (key > 0xff) {
					if(cterm->doorway_mode && ((key & 0xff) == 0) && key != 0x2c00 /* ALT-Z */) {
						ch[0]=0;
						ch[1]=key>>8;
						conn_send(ch,2,0);
						continue;
					}
deuce's avatar
deuce committed

			/* These keys are SyncTERM control keys */
			/* key is set to zero if consumed */
				case CIO_KEY_MOUSE:
					getmouse(&mevent);
					switch(mevent.event) {
						case CIOLIB_BUTTON_1_PRESS:
						case CIOLIB_BUTTON_1_RELEASE:
						case CIOLIB_BUTTON_2_PRESS:
						case CIOLIB_BUTTON_2_RELEASE:
						case CIOLIB_BUTTON_3_PRESS:
						case CIOLIB_BUTTON_3_RELEASE:
							conn_send(mouse_buf, fill_mevent(mouse_buf, sizeof(mouse_buf), &mevent, &ms), 0);
						case CIOLIB_BUTTON_4_PRESS:
						case CIOLIB_BUTTON_5_PRESS:
							if (ms.mode != 9 && ms.mode != 0) {
								conn_send(mouse_buf, fill_mevent(mouse_buf, sizeof(mouse_buf), &mevent, &ms), 0);
								break;
							}
							viewscroll();
							setup_mouse_events(&ms);
							break;
						case CIOLIB_BUTTON_1_DRAG_START:
						case CIOLIB_BUTTON_2_CLICK:
						case CIOLIB_BUTTON_3_CLICK:
							if (ms.mode == 9) {
								conn_send(mouse_buf, fill_mevent(mouse_buf, sizeof(mouse_buf), &mevent, &ms), 0);
							}
							else {
deuce's avatar
deuce committed
					key = 0;
				case CIO_KEY_SHIFT_IC:	/* Shift-Insert - Paste */
					do_paste();
					break;
				case 0x3000:	/* ALT-B - Scrollback */
					viewscroll();
					showmouse();
deuce's avatar
deuce committed
					key = 0;
					break;
				case 0x2e00:	/* ALT-C - Capture */
					capture_control(bbs);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
					break;
				case 0x2000:	/* ALT-D - Download */
deuce's avatar
deuce committed
					begin_download(bbs);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
				case 0x1200:	/* ALT-E */
					{
						char title[LIST_NAME_MAX + 12];
						struct ciolib_screen *savscrn;
						savscrn = savescreen();
						setfont(0, FALSE, 1);
						setfont(0, FALSE, 2);
						setfont(0, FALSE, 3);
						setfont(0, FALSE, 4);
						show_bbslist(bbs->name, TRUE);
						sprintf(title, "SyncTERM - %s\n", bbs->name);
						settitle(title);
						restorescreen(savscrn);
						freescreen(savscrn);
						if(cterm->scrollback != scrollback_buf || cterm->backlines != settings.backlines) {
							cterm->scrollback = scrollback_buf;
							cterm->backlines = settings.backlines;
							if(cterm->backpos>cterm->backlines)
								cterm->backpos=cterm->backlines;
						showmouse();
						_setcursortype(_NORMALCURSOR);
deuce's avatar
deuce committed
					font_control(bbs, cterm);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
					if(bbs->conn_type != CONN_TYPE_RLOGIN && bbs->conn_type != CONN_TYPE_RLOGIN_REVERSED && bbs->conn_type != CONN_TYPE_SSH) {
						if(bbs->user[0]) {
							conn_send(bbs->user,strlen(bbs->user),0);
							conn_send(cterm->emulation==CTERM_EMULATION_ATASCII?"\x9b":"\r",1,0);
							SLEEP(10);
						}
						if(bbs->password[0]) {
							conn_send(bbs->password,strlen(bbs->password),0);
							conn_send(cterm->emulation==CTERM_EMULATION_ATASCII?"\x9b":"\r",1,0);
						conn_send(bbs->syspass,strlen(bbs->syspass),0);
						conn_send(cterm->emulation==CTERM_EMULATION_ATASCII?"\x9b":"\r",1,0);
deuce's avatar
deuce committed
					key = 0;
deuce's avatar
deuce committed
				case 0x3200:	/* ALT-M */
					music_control(bbs);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
deuce's avatar
deuce committed
					break;
				case 0x1600:	/* ALT-U - Upload */
					begin_upload(bbs, FALSE, inch);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
deuce's avatar
deuce committed
				case 17:		/* CTRL-Q */
					if(cio_api.mode!=CIOLIB_MODE_CURSES
							&& cio_api.mode!=CIOLIB_MODE_CURSES_ASCII
							&& cio_api.mode!=CIOLIB_MODE_CURSES_IBM
							&& cio_api.mode!=CIOLIB_MODE_ANSI) {
						break;
					}
					if(cio_api.mode!=CIOLIB_MODE_CURSES
							&& cio_api.mode!=CIOLIB_MODE_CURSES_ASCII
							&& cio_api.mode!=CIOLIB_MODE_CURSES_IBM
							&& cio_api.mode!=CIOLIB_MODE_ANSI)
					/* FALLTHROUGH for curses/ansi modes */
				case 0x2d00:	/* Alt-X - Exit */
				case CIO_KEY_QUIT:
					if(!check_exit(TRUE))
						break;
					// Fallthrough
				case 0x2300:	/* Alt-H - Hangup */
deuce's avatar
deuce committed
					{
						struct ciolib_screen *savscrn;
						savscrn = savescreen();
						setfont(0, FALSE, 1);
						setfont(0, FALSE, 2);
						setfont(0, FALSE, 3);
						setfont(0, FALSE, 4);
						if(quitting || confirm("Disconnect... Are you sure?", "Selecting Yes closes the connection\n")) {
							freescreen(savscrn);
							cterm_clearscreen(cterm,cterm->attr);	/* Clear screen into scrollback */
							scrollback_lines=cterm->backpos;
							cterm_end(cterm);
deuce's avatar
deuce committed
							conn_close();
							hidemouse();
deuce's avatar
deuce committed
							hold_update=oldmc;
							return(key==0x2d00 /* Alt-X? */ || key == CIO_KEY_QUIT);
deuce's avatar
deuce committed
						}
						restorescreen(savscrn);
						freescreen(savscrn);
						showmouse();
deuce's avatar
deuce committed
					}
deuce's avatar
deuce committed
					key = 0;
deuce's avatar
deuce committed
					break;
					if(cio_api.mode!=CIOLIB_MODE_CURSES
							&& cio_api.mode!=CIOLIB_MODE_CURSES_IBM
							&& cio_api.mode!=CIOLIB_MODE_ANSI) {
						break;
					}
					/* FALLTHROUGH for curses/ansi modes */
				case 0x2c00:		/* ALT-Z */
					switch(syncmenu(bbs, &speed)) {
							cterm_clearscreen(cterm, cterm->attr);	/* Clear screen into scrollback */
							scrollback_lines=cterm->backpos;
							cterm_end(cterm);
							conn_close();
							hidemouse();
deuce's avatar
deuce committed
							hold_update=oldmc;
							return(FALSE);
						case 3:
							begin_upload(bbs, FALSE, inch);
							capture_control(bbs);
							break;
						case 8:
deuce's avatar
deuce committed
							music_control(bbs);
							break;
						case 9:
deuce's avatar
deuce committed
							font_control(bbs, cterm);
							cterm->doorway_mode=!cterm->doorway_mode;
deuce's avatar
deuce committed
							break;
deuce's avatar
deuce committed
						case 11:
deuce's avatar
deuce committed
							ooii_mode++;
							if(ooii_mode > MAX_OOII_MODE) {
								xptone_close();
deuce's avatar
deuce committed
								ooii_mode=0;
							cterm_clearscreen(cterm, cterm->attr);	/* Clear screen into scrollback */
							scrollback_lines=cterm->backpos;
							cterm_end(cterm);
							hidemouse();
deuce's avatar
deuce committed
							hold_update=oldmc;
								struct ciolib_screen *savscrn;
								char title[LIST_NAME_MAX + 12];

								savscrn = savescreen();
								setfont(0, FALSE, 1);
								setfont(0, FALSE, 2);
								setfont(0, FALSE, 3);
								setfont(0, FALSE, 4);
								show_bbslist(bbs->name, TRUE);
								sprintf(title, "SyncTERM - %s\n", bbs->name);
								settitle(title);
								restorescreen(savscrn);
								freescreen(savscrn);
					showmouse();
deuce's avatar
deuce committed
					key = 0;
				case 0x8d00:	/* CTRL-Up */
					if(bbs->conn_type != CONN_TYPE_SERIAL) {
						if(speed)
							speed=rates[get_rate_num(speed)+1];
						else
							speed=rates[0];
						key = 0;
					}
				case 0x9100:	/* CTRL-Down */