term.c 115 KB
Newer Older
deuce's avatar
deuce committed
1
2
/* Copyright (C), 2007 by Stephen Hurd */

3
/* $Id: term.c,v 1.387 2020/06/27 00:04:50 deuce Exp $ */
4

5
#include <assert.h>
deuce's avatar
deuce committed
6
#include <ciolib.h>
deuce's avatar
deuce committed
7
#include <cterm.h>
Deucе's avatar
Deucе committed
8
9
#include <genwrap.h>
#include <stdbool.h>
10
#include <vidmodes.h>
11

12
#include "conn.h"
Deucе's avatar
Deucе committed
13
#include "dirwrap.h"
rswindell's avatar
rswindell committed
14
#include "filepick.h"
Deucе's avatar
Deucе committed
15
16
#include "filewrap.h"
#include "gen_defs.h"
17
#include "menu.h"
Deucе's avatar
Deucе committed
18
#include "saucedefs.h"
deuce's avatar
deuce committed
19
#include "sexyz.h"
Deucе's avatar
Deucе committed
20
#include "syncterm.h"
21
#include "telnet_io.h"
Deucе's avatar
Deucе committed
22
23
24
25
26
27
28
29
#include "term.h"
#include "threadwrap.h"
#include "uifcinit.h"
#include "window.h"
#include "xmodem.h"
#include "xpbeep.h"
#include "xpendian.h"
#include "zmodem.h"
30

deuce's avatar
deuce committed
31
#ifndef WITHOUT_OOII
Deucе's avatar
Deucе committed
32
 #include "ooii.h"
deuce's avatar
deuce committed
33
#endif
34
35
#include "base64.h"
#include "md5.h"
36
#include "ripper.h"
deuce's avatar
deuce committed
37

Deucе's avatar
Deucе committed
38
#define ANSI_REPLY_BUFSIZE 2048
39
static char ansi_replybuf[2048];
deuce's avatar
deuce committed
40

41
42
#define DUMP

43
#ifndef MIN
Deucе's avatar
Deucе committed
44
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
45
46
#endif

47
48
struct terminal   term;
struct cterminal *cterm;
49

Deucе's avatar
Deucе committed
50
51
52
53
54
55
#define TRANSFER_WIN_WIDTH 66
#define TRANSFER_WIN_HEIGHT 18
static struct vmem_cell winbuf[(TRANSFER_WIN_WIDTH + 2) * (TRANSFER_WIN_HEIGHT + 1) * 2]; /* Save buffer for transfer
                                                                                           * window */
static struct text_info trans_ti;
static struct text_info log_ti;
56

57
58
static struct ciolib_pixels *pixmap_buffer[2];
static struct ciolib_mask *mask_buffer;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
static uint8_t pnm_gamma[256] = {
	0,  13, 22, 28, 34, 38, 42, 46, 50, 53, 56, 59, 61, 64, 66, 69,
	71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 93, 95, 96, 98, 
	99, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 
	117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 
	131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
	144, 145, 146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 
	155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, 165, 
	166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 
	175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 
	185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 
	193, 194, 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 
	201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207, 208, 208, 
	209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 
	216, 216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 
	223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 228, 229, 229, 
	230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 
	236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 
	242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 
	248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 
	254, 255, 255
};
uint8_t pnm_gamma_max = 255;
82

Deucе's avatar
Deucе committed
83
void
84
get_cterm_size(int *cols, int *rows, int ns)
85
86
87
{
	*cols = 80;
	*rows = 24;
Deucе's avatar
Deucе committed
88
	if (cterm != NULL) {
89
90
91
		*cols = cterm->width;
		*rows = cterm->height;
	}
92
	else {
93
		get_term_win_size(cols, rows, NULL, NULL, &ns);
94
	}
95
96
}

97
98
enum mouse_modes {
	MM_OFF,
99
	MM_RIP = 1,
100
101
102
103
104
105
106
107
	MM_X10 = 9,
	MM_NORMAL_TRACKING = 1000,
	MM_HIGHLIGHT_TRACKING = 1001,
	MM_BUTTON_EVENT_TRACKING = 1002,
	MM_ANY_EVENT_TRACKING = 1003
};

struct mouse_state {
Deucе's avatar
Deucе committed
108
109
110
111
	uint32_t         flags;

#define MS_FLAGS_SGR (1 << 0)
#define MS_SGR_SET (1006)
112
113
	enum mouse_modes mode;
};
114

Deucе's avatar
Deucе committed
115
void
116
setup_mouse_events(struct mouse_state *ms)
117
118
{
	ciomouse_setevents(0);
119
	if (ms) {
Deucе's avatar
Deucе committed
120
		switch (ms->mode) {
121
122
123
124
125
126
127
128
129
130
			case MM_RIP:
				ciomouse_addevent(CIOLIB_BUTTON_1_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_1_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_2_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_2_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_3_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_3_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
				mousepointer(CIOLIB_MOUSEPTR_ARROW);
				return;
131
132
			case MM_X10:
				ciomouse_addevent(CIOLIB_BUTTON_1_PRESS);
133
134
135
136
137
138
				ciomouse_addevent(CIOLIB_BUTTON_1_CLICK);
				ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_START);
				ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_MOVE);
				ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_END);
				ciomouse_addevent(CIOLIB_BUTTON_2_CLICK);
				ciomouse_addevent(CIOLIB_BUTTON_3_CLICK);
139
				ciomouse_addevent(CIOLIB_BUTTON_4_PRESS); // For scrollback...
140
				mousepointer(CIOLIB_MOUSEPTR_ARROW);
141
142
143
144
145
146
147
148
				return;
			case MM_NORMAL_TRACKING:
				ciomouse_addevent(CIOLIB_BUTTON_1_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_1_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_2_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_2_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_3_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_3_RELEASE);
149
150
				ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_5_PRESS);
151
				mousepointer(CIOLIB_MOUSEPTR_ARROW);
152
153
154
155
156
157
158
159
				return;
			case MM_BUTTON_EVENT_TRACKING:
				ciomouse_addevent(CIOLIB_BUTTON_1_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_1_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_2_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_2_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_3_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_3_RELEASE);
160
161
				ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_5_PRESS);
162
				ciomouse_addevent(CIOLIB_MOUSE_MOVE);
163
				mousepointer(CIOLIB_MOUSEPTR_ARROW);
164
165
166
167
168
169
170
171
				return;
			case MM_ANY_EVENT_TRACKING:
				ciomouse_addevent(CIOLIB_BUTTON_1_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_1_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_2_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_2_RELEASE);
				ciomouse_addevent(CIOLIB_BUTTON_3_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_3_RELEASE);
172
173
				ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
				ciomouse_addevent(CIOLIB_BUTTON_5_PRESS);
174
				ciomouse_addevent(CIOLIB_MOUSE_MOVE);
175
				mousepointer(CIOLIB_MOUSEPTR_ARROW);
176
177
178
179
180
				return;
			default:
				break;
		}
	}
181
182
183
184
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_START);
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_MOVE);
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_END);
	ciomouse_addevent(CIOLIB_BUTTON_2_CLICK);
185
	ciomouse_addevent(CIOLIB_BUTTON_3_CLICK);
186
	ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
187
	mousepointer(CIOLIB_MOUSEPTR_BAR);
188
189
}

190
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
191
 #pragma argsused
192
#endif
193

Deucе's avatar
Deucе committed
194
void
195
mousedrag(struct vmem_cell *scrollback)
196
{
197
198
199
200
201
202
203
204
205
206
207
208
	int                   key;
	struct mouse_event    mevent;
	struct vmem_cell     *screen;
	unsigned char        *tscreen;
	struct vmem_cell     *sbuffer;
	int                   sbufsize;
	int                   pos, startpos, endpos, lines;
	int                   outpos;
	char                 *copybuf = NULL;
	char                 *newcopybuf;
	int                   lastchar;
	struct ciolib_screen *savscrn;
Deucе's avatar
Deucе committed
209
210
211
212
213
214
215

	sbufsize = term.width * sizeof(*screen) * term.height;
	screen = malloc(sbufsize);
	sbuffer = malloc(sbufsize);
	tscreen = malloc(term.width * 2 * term.height);
	vmem_gettext(term.x - 1, term.y - 1, term.x + term.width - 2, term.y + term.height - 2, screen);
	gettext(term.x - 1, term.y - 1, term.x + term.width - 2, term.y + term.height - 2, tscreen);
216
	savscrn = savescreen();
217
	set_modepalette(palettes[COLOUR_PALETTE]);
Deucе's avatar
Deucе committed
218
219
220
221
222
	while (1) {
		key = getch();
		if ((key == 0) || (key == 0xe0))
			key |= getch() << 8;
		switch (key) {
223
224
			case CIO_KEY_MOUSE:
				getmouse(&mevent);
Deucе's avatar
Deucе committed
225
226
227
228
229
230
231
232
233
234
				startpos = ((mevent.starty - 1) * term.width) + (mevent.startx - 1);
				endpos = ((mevent.endy - 1) * term.width) + (mevent.endx - 1);
				if (startpos >= term.width * term.height)
					startpos = term.width * term.height - 1;
				if (endpos >= term.width * term.height)
					endpos = term.width * term.height - 1;
				if (endpos < startpos) {
					pos = endpos;
					endpos = startpos;
					startpos = pos;
235
				}
Deucе's avatar
Deucе committed
236
				switch (mevent.event) {
237
					case CIOLIB_BUTTON_1_DRAG_MOVE:
Deucе's avatar
Deucе committed
238
239
240
241
242
						memcpy(sbuffer, screen, sbufsize);
						for (pos = startpos; pos <= endpos; pos++) {
							if ((sbuffer[pos].legacy_attr & 0x70) != 0x10)
								sbuffer[pos].legacy_attr =
								    (sbuffer[pos].legacy_attr & 0x8F) | 0x10;
243
							else
Deucе's avatar
Deucе committed
244
245
246
247
248
								sbuffer[pos].legacy_attr =
								    (sbuffer[pos].legacy_attr & 0x8F) | 0x60;
							if (((sbuffer[pos].legacy_attr & 0x70) >> 4)
							    == (sbuffer[pos].legacy_attr & 0x0F))
								sbuffer[pos].legacy_attr |= 0x08;
249
250
251
							attr2palette(sbuffer[pos].legacy_attr,
							    &sbuffer[pos].fg,
							    &sbuffer[pos].bg);
252
						}
253
254
255
256
257
						vmem_puttext(term.x - 1,
						    term.y - 1,
						    term.x + term.width - 2,
						    term.y + term.height - 2,
						    sbuffer);
258
259
						break;
					default:
Deucе's avatar
Deucе committed
260
261
						lines = abs(mevent.endy - mevent.starty) + 1;
						newcopybuf = realloc(copybuf, (endpos - startpos + 4 + lines * 2) * 4);
262
263
264
265
						if (newcopybuf)
							copybuf = newcopybuf;
						else
							goto cleanup;
Deucе's avatar
Deucе committed
266
267
268
						outpos = 0;
						lastchar = 0;
						for (pos = startpos; pos <= endpos; pos++) {
269
270
							size_t   outlen;
							uint8_t *utf8str;
Deucе's avatar
Deucе committed
271

272
273
274
275
276
							utf8str =
							    cp_to_utf8(conio_fontdata[screen[pos].font].cp,
							        (char *)&screen[pos].ch,
							        1,
							        &outlen);
deuce's avatar
deuce committed
277
278
279
280
							if (utf8str == NULL)
								continue;
							memcpy(copybuf + outpos, utf8str, outlen);
							outpos += outlen;
Deucе's avatar
Deucе committed
281
282
283
284
285
286
287
288
289
							if ((screen[pos].ch != ' ') && screen[pos].ch)
								lastchar = outpos;
							if ((pos + 1) % term.width == 0) {
								outpos = lastchar;
#ifdef _WIN32
								copybuf[outpos++] = '\r';
#endif
								copybuf[outpos++] = '\n';
								lastchar = outpos;
290
291
							}
						}
Deucе's avatar
Deucе committed
292
						copybuf[outpos] = 0;
293
						copytext(copybuf, strlen(copybuf));
294
295
296
297
298
						vmem_puttext(term.x - 1,
						    term.y - 1,
						    term.x + term.width - 2,
						    term.y + term.height - 2,
						    screen);
299
						goto cleanup;
300
301
302
				}
				break;
			default:
303
304
305
306
307
				vmem_puttext(term.x - 1,
				    term.y - 1,
				    term.x + term.width - 2,
				    term.y + term.height - 2,
				    screen);
308
				ungetch(key);
309
				goto cleanup;
310
311
		}
	}
312
313
314
315
316

cleanup:
	free(screen);
	free(sbuffer);
	free(tscreen);
Deucе's avatar
Deucе committed
317
	if (copybuf)
318
		free(copybuf);
319
320
	restorescreen(savscrn);
	freescreen(savscrn);
321
	return;
322
}
323

Deucе's avatar
Deucе committed
324
void
325
update_status(struct bbslist *bbs, int speed, int ooii_mode)
deuce's avatar
deuce committed
326
{
327
328
329
330
	char nbuf[LIST_NAME_MAX + 10 + 11 + 1]; /*
                                                 * Room for "Name (Logging) (115300)" and terminator
                                                 * SAFE and Logging should me be possible.
                                                 */
Deucе's avatar
Deucе committed
331
332
333
334
335
336
337
338
339
340
	int               oldscroll;
	int               olddmc = hold_update;
	struct  text_info txtinfo;
	time_t            now;
	static time_t     lastupd = 0;
	static int        oldspeed = 0;
	int               timeon;
	char              sep;
	int               oldfont_norm;
	int               oldfont_bright;
341

342
343
344
	if (term.nostatus)
		return;

Deucе's avatar
Deucе committed
345
346
	oldfont_norm = getfont(1);
	oldfont_bright = getfont(2);
347
348
	setfont(0, false, 1);
	setfont(0, false, 2);
Deucе's avatar
Deucе committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
	switch (getfont(1)) {
		case 0:
		case 17:
		case 18:
		case 19:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 31:
			sep = 0xb3;
			break;
		default:
			sep = '|';
364
	}
Deucе's avatar
Deucе committed
365
366
367
368
	now = time(NULL);
	if ((now == lastupd) && (speed == oldspeed)) {
		setfont(oldfont_norm, 0, 1);
		setfont(oldfont_bright, 0, 2);
deuce's avatar
deuce committed
369
		return;
370
	}
Deucе's avatar
Deucе committed
371
372
	lastupd = now;
	oldspeed = speed;
373
374
375
376
377
	if (now > (bbs->connected + 359999))
		timeon = 350000;
	else if (now < bbs->connected)
		timeon = 0;
	else
Deucе's avatar
Deucе committed
378
		timeon = (int)(now - bbs->connected);
379
	gettextinfo(&txtinfo);
Deucе's avatar
Deucе committed
380
381
382
383
384
385
386
387
	oldscroll = _wscroll;
	hold_update = true;
	textattr(YELLOW | (BLUE << 4));

        /* Move to status line thinger */
	window(term.x - 1, term.y + term.height - 1, term.x + term.width - 2, term.y + term.height - 1);
	gotoxy(1, 1);
	_wscroll = 0;
388
	strcpy(nbuf, bbs->name);
Deucе's avatar
Deucе committed
389
	if (safe_mode)
390
		strcat(nbuf, " (SAFE)");
Deucе's avatar
Deucе committed
391
	if (cterm->log)
392
		strcat(nbuf, " (Logging)");
Deucе's avatar
Deucе committed
393
394
395
	if (speed)
		sprintf(strchr(nbuf, 0), " (%d)", speed);
	if (cterm->doorway_mode)
deuce's avatar
deuce committed
396
		strcat(nbuf, " (DrWy)");
Deucе's avatar
Deucе committed
397
398
399
400
401
402
403
404
405
406
	switch (ooii_mode) {
		case 1:
			strcat(nbuf, " (OOTerm)");
			break;
		case 2:
			strcat(nbuf, " (OOTerm1)");
			break;
		case 3:
			strcat(nbuf, " (OOTerm2)");
			break;
deuce's avatar
deuce committed
407
	}
408
	ciolib_setcolour(11, 4);
Deucе's avatar
Deucе committed
409
	switch (cio_api.mode) {
410
411
412
		case CIOLIB_MODE_CURSES:
		case CIOLIB_MODE_CURSES_IBM:
		case CIOLIB_MODE_ANSI:
413
			if (timeon > 359999) {
414
415
416
417
418
419
				cprintf(" %-29.29s %c %-6.6s %c Connected: Too Long %c CTRL-S for menu ",
				    nbuf,
				    sep,
				    conn_types[bbs->conn_type],
				    sep,
				    sep);
420
421
			}
			else {
422
423
424
425
426
427
428
429
430
				cprintf(" %-29.29s %c %-6.6s %c Connected: %02d:%02d:%02d %c CTRL-S for menu ",
				    nbuf,
				    sep,
				    conn_types[bbs->conn_type],
				    sep,
				    timeon / 3600,
				    (timeon / 60) % 60,
				    timeon % 60,
				    sep);
431
			}
432
433
			break;
		default:
434
			if (timeon > 359999) {
435
436
437
438
439
440
				cprintf(" %-30.30s %c %-6.6s %c Connected: Too Long %c "ALT_KEY_NAME3CH "-Z for menu ",
				    nbuf,
				    sep,
				    conn_types[bbs->conn_type],
				    sep,
				    sep);
441
442
			}
			else {
443
444
445
446
447
448
449
450
451
452
				cprintf(
					" %-30.30s %c %-6.6s %c Connected: %02d:%02d:%02d %c "ALT_KEY_NAME3CH "-Z for menu ",
					nbuf,
					sep,
					conn_types[bbs->conn_type],
					sep,
					timeon / 3600,
					(timeon / 60) % 60,
					timeon % 60,
					sep);
453
			}
454
			break; /*    1+29     +3    +6    +3    +11        +3+3+2        +3    +6    +4  +5 */
455
	}
Deucе's avatar
Deucе committed
456
	if (wherex() >= 80)
457
		clreol();
Deucе's avatar
Deucе committed
458
459
460
	_wscroll = oldscroll;
	setfont(oldfont_norm, 0, 1);
	setfont(oldfont_bright, 0, 2);
deuce's avatar
deuce committed
461
	textattr(txtinfo.attribute);
Deucе's avatar
Deucе committed
462
463
464
	window(txtinfo.winleft, txtinfo.wintop, txtinfo.winright, txtinfo.winbottom);
	gotoxy(txtinfo.curx, txtinfo.cury);
	hold_update = olddmc;
deuce's avatar
deuce committed
465
466
}

467
#if defined(_WIN32) && defined(_DEBUG) && defined(DUMP)
468

Deucе's avatar
Deucе committed
469
void
470
dump(BYTE *buf, int len)
471
{
Deucе's avatar
Deucе committed
472
473
474
475
476
477
478
479
	char   str[128];
	int    i, j;
	size_t slen = 0;

	slen = sprintf(str, "RX: ");
	for (i = 0; i < len; i += j) {
		for (j = 0; i + j < len && j < 32; j++)
			slen += sprintf(str + slen, "%02X ", buf[i + j]);
480
		OutputDebugString(str);
Deucе's avatar
Deucе committed
481
		slen = sprintf(str, "RX: ");
482
483
	}
}
Deucе's avatar
Deucе committed
484
485

#endif /* if defined(_WIN32) && defined(_DEBUG) && defined(DUMP) */
486

487
/* Zmodem Stuff */
488
int log_level = LOG_INFO;
489

490
struct zmodem_cbdata {
491
492
	zmodem_t       *zm;
	struct bbslist *bbs;
493
494
};

Deucе's avatar
Deucе committed
495
496
497
498
enum {
	ZMODEM_MODE_SEND,
	ZMODEM_MODE_RECV
} zmodem_mode;
499

Deucе's avatar
Deucе committed
500
static BOOL
501
zmodem_check_abort(void *vp)
502
{
503
504
505
506
507
	struct zmodem_cbdata *zcb = (struct zmodem_cbdata *)vp;
	zmodem_t             *zm = zcb->zm;
	static time_t         last_check = 0;
	time_t                now = time(NULL);
	int                   key;
508

deuce's avatar
deuce committed
509
	if (zm == NULL)
510
		return true;
deuce's avatar
deuce committed
511
	if (quitting) {
Deucе's avatar
Deucе committed
512
513
		zm->cancelled = true;
		zm->local_abort = true;
514
		return true;
515
	}
Deucе's avatar
Deucе committed
516
517
518
519
	if (last_check != now) {
		last_check = now;
		while (kbhit()) {
			switch ((key = getch())) {
deuce's avatar
deuce committed
520
521
522
				case ESC:
				case CTRL_C:
				case CTRL_X:
Deucе's avatar
Deucе committed
523
524
					zm->cancelled = true;
					zm->local_abort = true;
deuce's avatar
deuce committed
525
526
527
528
					break;
				case 0:
				case 0xe0:
					key |= (getch() << 8);
Deucе's avatar
Deucе committed
529
					if (key == CIO_KEY_MOUSE)
deuce's avatar
deuce committed
530
						getmouse(NULL);
Deucе's avatar
Deucе committed
531
					if (key == CIO_KEY_QUIT) {
532
						if (check_exit(false)) {
Deucе's avatar
Deucе committed
533
534
							zm->cancelled = true;
							zm->local_abort = true;
535
						}
deuce's avatar
deuce committed
536
537
					}
					break;
538
			}
539
540
		}
	}
Deucе's avatar
Deucе committed
541
	return zm->cancelled;
542
543
}

544
545
extern FILE *log_fp;
extern char *log_levels[];
546

547
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
548
 #pragma argsused
549
#endif
550

Deucе's avatar
Deucе committed
551
static int
552
lputs(void *cbdata, int level, const char *str)
553
554
{
	char msg[512];
Deucе's avatar
Deucе committed
555
556
	int  chars;
	int  oldhold = hold_update;
557

558
#if defined(_WIN32) && defined(_DEBUG) && false
Deucе's avatar
Deucе committed
559
	sprintf(msg, "SyncTerm: %s\n", str);
560
	OutputDebugString(msg);
561
#endif
562

Deucе's avatar
Deucе committed
563
	if ((log_fp != NULL) && (level <= log_level)) {
564
		time_t t = time(NULL);
Deucе's avatar
Deucе committed
565
		fprintf(log_fp, "%.15s %s\n", ctime(&t) + 4, str);
566
	}
567

Deucе's avatar
Deucе committed
568
	if (level > LOG_INFO)
569
		return 0;
570

Deucе's avatar
Deucе committed
571
        /* Assumes the receive window has been drawn! */
572
573
	window(log_ti.winleft, log_ti.wintop, log_ti.winright, log_ti.winbottom);
	gotoxy(log_ti.curx, log_ti.cury);
574
	textbackground(BLUE);
Deucе's avatar
Deucе committed
575
576
	switch (level) {
#if 0 // Not possible because of above level > LOG_INFO check
577
		case LOG_DEBUG:
578
			textcolor(LIGHTCYAN);
Deucе's avatar
Deucе committed
579
			SAFEPRINTF(msg, "%s\r\n", str);
580
			break;
deuce's avatar
deuce committed
581
#endif
deuce's avatar
deuce committed
582
		case LOG_INFO:
583
			textcolor(WHITE);
Deucе's avatar
Deucе committed
584
			SAFEPRINTF(msg, "%s\r\n", str);
585
			break;
586
587
		case LOG_NOTICE:
			textcolor(YELLOW);
Deucе's avatar
Deucе committed
588
			SAFEPRINTF(msg, "%s\r\n", str);
589
			break;
590
		case LOG_WARNING:
591
			textcolor(LIGHTMAGENTA);
Deucе's avatar
Deucе committed
592
			SAFEPRINTF(msg, "Warning: %s\r\n", str);
593
594
			break;
		default:
595
			textcolor(LIGHTRED);
Deucе's avatar
Deucе committed
596
			SAFEPRINTF(msg, "!ERROR: %s\r\n", str);
597
598
			break;
	}
Deucе's avatar
Deucе committed
599
600
601
	hold_update = false;
	chars = cputs(msg);
	hold_update = oldhold;
602
	gettextinfo(&log_ti);
603

deuce's avatar
deuce committed
604
	return chars;
605
}
606

Deucе's avatar
Deucе committed
607
static int
608
lprintf(int level, const char *fmt, ...)
609
{
Deucе's avatar
Deucе committed
610
	char    sbuf[1024];
611
612
	va_list argptr;

Deucе's avatar
Deucе committed
613
614
615
616
617
	va_start(argptr, fmt);
	vsnprintf(sbuf, sizeof(sbuf), fmt, argptr);
	sbuf[sizeof(sbuf) - 1] = 0;
	va_end(argptr);
	return lputs(NULL, level, sbuf);
618
619
}

620
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
621
 #pragma argsused
622
#endif
623

Deucе's avatar
Deucе committed
624
void
625
zmodem_progress(void *cbdata, int64_t current_pos)
626
{
627
628
629
630
631
632
633
634
635
636
	char                  orig[128];
	unsigned              cps;
	int                   l;
	time_t                t;
	time_t                now;
	static time_t         last_progress = 0;
	int                   old_hold = hold_update;
	struct zmodem_cbdata *zcb = (struct zmodem_cbdata *)cbdata;
	zmodem_t             *zm = zcb->zm;
	bool                  growing = false;
Deucе's avatar
Deucе committed
637
638
639
640
641

	now = time(NULL);
	if (current_pos > zm->current_file_size)
		growing = true;
	if ((now != last_progress) || ((current_pos >= zm->current_file_size) && (growing == false))) {
642
		zmodem_check_abort(cbdata);
643
		hold_update = true;
644
645
646
647
		window(((trans_ti.screenwidth - TRANSFER_WIN_WIDTH) / 2) + 2,
		    ((trans_ti.screenheight - TRANSFER_WIN_HEIGHT) / 2) + 1,
		    ((trans_ti.screenwidth - TRANSFER_WIN_WIDTH) / 2) + TRANSFER_WIN_WIDTH - 2,
		    ((trans_ti.screenheight - TRANSFER_WIN_HEIGHT) / 2) + 5);
Deucе's avatar
Deucе committed
648
649
650
651
652
653
654
655
656
657
658
659
		gotoxy(1, 1);
		textattr(LIGHTCYAN | (BLUE << 4));
		t = now - zm->transfer_start_time;
		if (t <= 0)
			t = 1;
		if (zm->transfer_start_pos > current_pos)
			zm->transfer_start_pos = 0;
		if ((cps = (unsigned)((current_pos - zm->transfer_start_pos) / t)) == 0)
			cps = 1;                                 /* cps so far */
		l = (zm->current_file_size - current_pos) / cps; /* remaining transfer est time */
		if (l < 0)
			l = 0;
660
661
		cprintf("File (%u of %u): %-.*s",
		    zm->current_file_num, zm->total_files, TRANSFER_WIN_WIDTH - 20, zm->current_file_name);
662
663
		clreol();
		cputs("\r\n");
Deucе's avatar
Deucе committed
664
665
		if (zm->transfer_start_pos)
			sprintf(orig, "From: %" PRId64 "  ", zm->transfer_start_pos);
666
		else
Deucе's avatar
Deucе committed
667
			orig[0] = 0;
668
669
		cprintf("%sByte: %" PRId64 " of %" PRId64 " (%" PRId64 " KB)",
		    orig, current_pos, zm->current_file_size, zm->current_file_size / 1024);
670
671
		clreol();
		cputs("\r\n");
672
		cprintf("Time: %lu:%02lu  ETA: %lu:%02lu  Block: %u/CRC-%u  %u cps"
Deucе's avatar
Deucе committed
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
		    ,
		    (unsigned long)(t / 60L)
		    ,
		    (unsigned long)(t % 60L)
		    ,
		    (unsigned long)(l / 60L)
		    ,
		    (unsigned long)(l % 60L)
		    ,
		    zm->block_size
		    ,
		    zmodem_mode == ZMODEM_MODE_RECV ? (zm->receive_32bit_data ? 32 : 16)
		                                                              : (zm->can_fcs_32 && !zm->want_fcs_16) ? 32 : 16
		    ,
		    cps);
688
		clreol();
689
		cputs("\r\n");
Deucе's avatar
Deucе committed
690
691
		if (zm->current_file_size == 0) {
			cprintf("%*s%3d%%\r\n", TRANSFER_WIN_WIDTH / 2 - 5, "", 100);
692
693
			l = 60;
		}
Deucе's avatar
Deucе committed
694
		else {
695
696
			cprintf("%*s%3d%%\r\n", TRANSFER_WIN_WIDTH / 2 - 5, "",
			    (long)(((float)current_pos / (float)zm->current_file_size) * 100.0));
Deucе's avatar
Deucе committed
697
			l = (long)(60 * ((float)current_pos / (float)zm->current_file_size));
698
		}
699
		cprintf("[%*.*s%*s]", l, l,
Deucе's avatar
Deucе committed
700
701
702
703
704
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
705
706
		    "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1",
		    (int)(60 - l), "");
Deucе's avatar
Deucе committed
707
		last_progress = now;
708
		hold_update = false;
709
710
		gotoxy(wherex(), wherey());
		hold_update = old_hold;
711
	}
712
713
}

714
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
715
 #pragma argsused
716
#endif
deuce's avatar
deuce committed
717

Deucе's avatar
Deucе committed
718
719
unsigned char transfer_buffer[BUFFER_SIZE / 2];
unsigned      transfer_buf_len = 0;
720

Deucе's avatar
Deucе committed
721
static void
722
flush_send(void *unused)
deuce's avatar
deuce committed
723
{
Deucе's avatar
Deucе committed
724
	int sent;
deuce's avatar
deuce committed
725

Deucе's avatar
Deucе committed
726
727
728
	sent = conn_send(transfer_buffer, transfer_buf_len, 120 * 1000);
	if (sent < transfer_buf_len) {
		memmove(transfer_buffer, transfer_buffer + sent, transfer_buf_len - sent);
deuce's avatar
deuce committed
729
730
		transfer_buf_len -= sent;
	}
Deucе's avatar
Deucе committed
731
732
733
	else {
		transfer_buf_len = 0;
	}
deuce's avatar
deuce committed
734
}
735

Deucе's avatar
Deucе committed
736
static int
737
send_byte(void *unused, uchar ch, unsigned timeout /* seconds */)
738
{
Deucе's avatar
Deucе committed
739
740
	transfer_buffer[transfer_buf_len++] = ch;
	if (transfer_buf_len == sizeof(transfer_buffer))
deuce's avatar
deuce committed
741
		flush_send(unused);
Deucе's avatar
Deucе committed
742
	return !(transfer_buf_len < sizeof(transfer_buffer));
743
744
}

745
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
746
 #pragma argsused
747
#endif
Deucе's avatar
Deucе committed
748
749
750
BYTE     recv_byte_buffer[BUFFER_SIZE];
unsigned recv_byte_buffer_len = 0;
unsigned recv_byte_buffer_pos = 0;
751

Deucе's avatar
Deucе committed
752
753
static void
recv_bytes(unsigned timeout /* Milliseconds */)
754
{
Deucе's avatar
Deucе committed
755
	if (recv_byte_buffer_len == 0) {
756
757
		recv_byte_buffer_len = parse_rip(recv_byte_buffer, 0, sizeof(recv_byte_buffer));
		if (recv_byte_buffer_len == 0) {
Deucе's avatar
Deucе committed
758
			recv_byte_buffer_len = conn_recv_upto(recv_byte_buffer, sizeof(recv_byte_buffer) - 3, timeout);
759
			if (recv_byte_buffer_len)
Deucе's avatar
Deucе committed
760
761
				recv_byte_buffer_len =
				    parse_rip(recv_byte_buffer, recv_byte_buffer_len, sizeof(recv_byte_buffer));
762
763
		}
	}
764
}
765

Deucе's avatar
Deucе committed
766
static int
767
recv_byte(void *unused, unsigned timeout /* seconds */)
768
{
769
770
	BYTE ch;

Deucе's avatar
Deucе committed
771
	recv_bytes(timeout * 1000);
772

Deucе's avatar
Deucе committed
773
774
775
776
	if (recv_byte_buffer_len > 0) {
		ch = recv_byte_buffer[recv_byte_buffer_pos++];
		if (recv_byte_buffer_pos == recv_byte_buffer_len)
			recv_byte_buffer_len = recv_byte_buffer_pos = 0;
777
778
		return ch;
	}
779

780
	return -1;
781
782
}

783
#if defined(__BORLANDC__)
Deucе's avatar
Deucе committed
784
 #pragma argsused
785
#endif
786

Deucе's avatar
Deucе committed
787
BOOL
788
data_waiting(void *unused, unsigned timeout /* seconds */)
789
{
Deucе's avatar
Deucе committed
790
	bool ret;
deuce's avatar
deuce committed
791

Deucе's avatar
Deucе committed
792
	if (recv_byte_buffer_len)
793
		return true;
deuce's avatar
deuce committed
794
	pthread_mutex_lock(&(conn_inbuf.mutex));
Deucе's avatar
Deucе committed
795
	ret = conn_buf_wait_bytes(&conn_inbuf, 1, timeout * 1000) != 0;
deuce's avatar
deuce committed
796
797
	pthread_mutex_unlock(&(conn_inbuf.mutex));
	return ret;
798
}
799

Deucе's avatar
Deucе committed
800
801
size_t
count_data_waiting(void)
802
803
804
805
{
	recv_bytes(0);
	return recv_byte_buffer_len;
}
806

Deucе's avatar
Deucе committed
807
void
808
draw_transfer_window(char *title)
809
{
Deucе's avatar
Deucе committed
810
811
812
	char outline[TRANSFER_WIN_WIDTH * 2];
	char shadow[TRANSFER_WIN_WIDTH * 2]; /* Assumes that width*2 > height * 2 */
	int  i, top, left, old_hold;
813

814
	old_hold = hold_update;
Deucе's avatar
Deucе committed
815
	hold_update = true;
816
	gettextinfo(&trans_ti);
Deucе's avatar
Deucе committed
817
818
	top = (trans_ti.screenheight - TRANSFER_WIN_HEIGHT) / 2;
	left = (trans_ti.screenwidth - TRANSFER_WIN_WIDTH) / 2;
819
820
	window(1, 1, trans_ti.screenwidth, trans_ti.screenheight);

821
	vmem_gettext(left, top, left + TRANSFER_WIN_WIDTH + 1, top + TRANSFER_WIN_HEIGHT, winbuf);
Deucе's avatar
Deucе committed
822
823
824
	memset(outline, YELLOW | (BLUE << 4), sizeof(outline));
	for (i = 2; i < sizeof(outline) - 2; i += 2) {
		outline[i] = (char)0xcd; /* Double horizontal line */
825
	}
Deucе's avatar
Deucе committed
826
827
	outline[0] = (char)0xc9;
	outline[sizeof(outline) - 2] = (char)0xbb;
828
	puttext(left, top, left + TRANSFER_WIN_WIDTH - 1, top, outline);
829

Deucе's avatar
Deucе committed
830
831
832
833
834
835
836
        /* Title */
	gotoxy(left + 4, top);
	textattr(YELLOW | (BLUE << 4));
	cprintf("\xb5 %*s \xc6", strlen(title), "");
	gotoxy(left + 6, top);
	textattr(WHITE | (BLUE << 4));
	cprintf("%s", title);
837

Deucе's avatar
Deucе committed
838
839
	for (i = 2; i < sizeof(outline) - 2; i += 2) {
		outline[i] = (char)0xc4;           /* Single horizontal line */
840
	}
Deucе's avatar
Deucе committed
841
842
843
	outline[0] = (char)0xc7;                   /* 0xcc */
	outline[sizeof(outline) - 2] = (char)0xb6; /* 0xb6 */
	puttext(left, top + 6, left + TRANSFER_WIN_WIDTH - 1, top + 6, outline);
844

Deucе's avatar
Deucе committed
845
846
	for (i = 2; i < sizeof(outline) - 2; i += 2) {
		outline[i] = (char)0xcd; /* Double horizontal line */
847
	}
Deucе's avatar
Deucе committed
848
849
	outline[0] = (char)0xc8;
	outline[sizeof(outline) - 2] = (char)0xbc;
850
851
852
853
854
	puttext(left,
	    top + TRANSFER_WIN_HEIGHT - 1,
	    left + TRANSFER_WIN_WIDTH - 1,
	    top + TRANSFER_WIN_HEIGHT - 1,
	    outline);
Deucе's avatar
Deucе committed
855
856
857
	outline[0] = (char)0xba;
	outline[sizeof(outline) - 2] = (char)0xba;
	for (i = 2; i < sizeof(outline) - 2; i += 2)
858
		outline[i] = ' ';
Deucе's avatar
Deucе committed
859
860
	for (i = 1; i < 6; i++)
		puttext(left, top + i, left + TRANSFER_WIN_WIDTH - 1, top + i, outline);
861

Deucе's avatar
Deucе committed
862
863
864
865
866
867
868
/*
 *      for(i=3;i < sizeof(outline) - 2; i+=2) {
 *              outline[i] = LIGHTGRAY | (BLACK << 8);
 *      }
 */
	for (i = 7; i < TRANSFER_WIN_HEIGHT - 1; i++)
		puttext(left, top + i, left + TRANSFER_WIN_WIDTH - 1, top + i, outline);
869

Deucе's avatar
Deucе committed
870
        /* Title */
871
	gotoxy(left + TRANSFER_WIN_WIDTH - 20, top + i);
Deucе's avatar
Deucе committed
872
	textattr(YELLOW | (BLUE << 4));
873
	cprintf("\xb5              \xc6");
Deucе's avatar
Deucе committed
874
	textattr(WHITE | (BLUE << 4));
875
876
877
	gotoxy(left + TRANSFER_WIN_WIDTH - 18, top + i);
	cprintf("ESC to Abort");

Deucе's avatar
Deucе committed
878
879
        /* Shadow */
	if (uifc.bclr == BLUE) {
880
881
882
883
884
		gettext(left + TRANSFER_WIN_WIDTH,
		    top + 1,
		    left + TRANSFER_WIN_WIDTH + 1,
		    top + (TRANSFER_WIN_HEIGHT - 1),
		    shadow);
Deucе's avatar
Deucе committed
885
886
		for (i = 1; i < sizeof(shadow); i += 2)
			shadow[i] = DARKGRAY;
887
888
889
890
891
892
893
894
895
896
		puttext(left + TRANSFER_WIN_WIDTH,
		    top + 1,
		    left + TRANSFER_WIN_WIDTH + 1,
		    top + (TRANSFER_WIN_HEIGHT - 1),
		    shadow);
		gettext(left + 2,
		    top + TRANSFER_WIN_HEIGHT,
		    left + TRANSFER_WIN_WIDTH + 1,
		    top + TRANSFER_WIN_HEIGHT,
		    shadow);
Deucе's avatar
Deucе committed
897
898
		for (i = 1; i < sizeof(shadow); i += 2)
			shadow[i] = DARKGRAY;
899
900
901
902
903
		puttext(left + 2,
		    top + TRANSFER_WIN_HEIGHT,
		    left + TRANSFER_WIN_WIDTH + 1,
		    top + TRANSFER_WIN_HEIGHT,
		    shadow);
904
905
	}

Deucе's avatar
Deucе committed
906
	window(left + 2, top + 7, left + TRANSFER_WIN_WIDTH - 3, top + TRANSFER_WIN_HEIGHT - 2);
907
	hold_update = false;
Deucе's avatar
Deucе committed
908
	gotoxy(1, 1);
909
	hold_update = old_hold;
910
	gettextinfo(&log_ti);
911
	_setcursortype(_NOCURSOR);
912
}
913

Deucе's avatar
Deucе committed
914
915
916
void
erase_transfer_window(void)
{
917
918
919
920
921
	vmem_puttext(((trans_ti.screenwidth - TRANSFER_WIN_WIDTH) / 2),
	    ((trans_ti.screenheight - TRANSFER_WIN_HEIGHT) / 2),
	    ((trans_ti.screenwidth - TRANSFER_WIN_WIDTH) / 2) + TRANSFER_WIN_WIDTH + 1,
	    ((trans_ti.screenheight - TRANSFER_WIN_HEIGHT) / 2) + TRANSFER_WIN_HEIGHT,
	    winbuf);
922
923
924
	window(trans_ti.winleft, trans_ti.wintop, trans_ti.winright, trans_ti.winbottom);
	gotoxy(trans_ti.curx, trans_ti.cury);
	textattr(trans_ti.attribute);
925
	_setcursortype(_NORMALCURSOR);
926
}
927
928
void ascii_upload(FILE *fp);
void raw_upload(FILE *fp);
929