xref: /csrg-svn/usr.bin/tn3270/ctlr/api.c (revision 31226)
1 /*
2  * This file implements the API used in the PC version.
3  */
4 
5 #include <stdio.h>
6 
7 #include "api.h"
8 #include "../general/general.h"
9 
10 #include "../ascii/disp_asc.h"
11 
12 #include "../ctlr/screen.h"
13 #include "../ctlr/oia.h"
14 
15 #include "../general/globals.h"
16 
17 /*
18  * General utility routines.
19  */
20 
21 #if	defined(MSDOS)
22 
23 #if	defined(LINT_ARGS)
24 static void movetous(char *, int, int, int);
25 static void movetothem(int, int, char *, int);
26 #endif	/* defined(LINT_ARGS) */
27 
28 #define	access(foo,length)	(foo)
29 #define	unaccess(foo,goo,length)
30 
31 static void
32 movetous(parms, es, di, length)
33 char *parms;
34 int es, di, length;
35 {
36     char far *farparms = parms;
37 
38     movedata(es, di, (int) FP_SEG(farparms), (int) FP_OFF(farparms), length);
39 }
40 
41 static void
42 movetothem(es, di, parms, length)
43 int es, di;
44 char *parms;
45 int length;
46 {
47     char far *farparms = parms;
48 
49     movedata((int) FP_SEG(farparms), (int) FP_OFF(farparms), es, di, length);
50 }
51 #endif	/* defined(MSDOS) */
52 
53 /* No Unix version yet... */
54 
55 #if	defined(unix)
56 #define	access(f,l)	(f)
57 
58 #endif	/* defined(unix) */
59 
60 /*
61  * Supervisor Services.
62  */
63 
64 static void
65 name_resolution(regs, sregs)
66 union REGS *regs;
67 struct SREGS *sregs;
68 {
69     NameResolveParms parms;
70 
71     movetous((char *) &parms, sregs->es, regs->x.di, sizeof parms);
72 
73     regs->h.cl = 0;
74     if (memcmp((char *)&parms, NAME_SESSMGR, sizeof parms.gate_name) == 0) {
75 	regs->x.dx = GATE_SESSMGR;
76     } else if (memcmp((char *)&parms, NAME_KEYBOARD,
77 					sizeof parms.gate_name) == 0) {
78 	regs->x.dx = GATE_KEYBOARD;
79     } else if (memcmp((char *)&parms, NAME_COPY, sizeof parms.gate_name) == 0) {
80 	regs->x.dx = GATE_COPY;
81     } else if (memcmp((char *)&parms, NAME_OIAM, sizeof parms.gate_name) == 0) {
82 	regs->x.dx = GATE_OIAM;
83     } else {
84 	regs->h.cl = 0x2e;	/* Name not found */
85     }
86     regs->h.ch = 0x12;
87     regs->h.bh = 7;
88 }
89 
90 /*
91  * Session Information Services.
92  */
93 
94 static void
95 query_session_id(regs, sregs)
96 union REGS *regs;
97 struct SREGS *sregs;
98 {
99     QuerySessionIdParms parms;
100 
101     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
102 
103     if ((parms.rc != 0) || (parms.function_id != 0)) {
104 	parms.rc = 0x0c;
105     } else if (parms.option_code != 0x01) {
106 	parms.rc = 0x0d;	/* Invalid option code */
107     } else if (parms.data_code != 0x45) {
108 	parms.rc = 0x0b;
109     } else {
110 	NameArray list;
111 	NameArrayElement element;
112 
113 	movetous((char *)&list, FP_SEG(parms.name_array),
114 			    FP_OFF(parms.name_array), sizeof list);
115 	if ((list.length < 14) || (list.length > 170)) {
116 	    parms.rc = 0x12;
117 	} else {
118 	    list.number_matching_session = 1;
119 	    list.name_array_element.short_name = parms.data_code;
120 	    list.name_array_element.type = TYPE_DFT;
121 	    list.name_array_element.session_id = 23;
122 	    memcpy(list.name_array_element.long_name, "ONLYSESS",
123 			    sizeof list.name_array_element.long_name);
124 	    movetothem(FP_SEG(parms.name_array),
125 		FP_OFF(parms.name_array), (char *)&list, sizeof list);
126 	    parms.rc = 0;
127 	}
128     }
129     parms.function_id = 0x6b;
130     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
131 }
132 
133 static void
134 query_session_parameters(regs, sregs)
135 union REGS *regs;
136 struct SREGS *sregs;
137 {
138     QuerySessionParametersParms parms;
139 
140     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
141 
142     if ((parms.rc !=0) || (parms.function_id != 0)) {
143 	parms.rc = 0x0c;
144     } else if (parms.session_id != 23) {
145 	parms.rc = 0x02;
146     } else {
147 	parms.rc = 0;
148 	parms.session_type = TYPE_DFT;
149 	parms.session_characteristics = 0;	/* Neither EAB nor PSS */
150 	parms.rows = MaxNumberLines;
151 	parms.columns = MaxNumberColumns;
152 	parms.presentation_space = 0;
153     }
154     parms.function_id = 0x6b;
155     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
156 }
157 
158 static void
159 query_session_cursor(regs, sregs)
160 union REGS *regs;
161 struct SREGS *sregs;
162 {
163     QuerySessionCursorParms parms;
164 
165     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
166 
167     if ((parms.rc != 0) || (parms.function_id != 0)) {
168 	parms.rc = 0x0c;
169     } else if (parms.session_id != 23) {
170 	parms.rc = 0x02;
171     } else {
172 	parms.rc = 0;
173 	parms.cursor_type = CURSOR_BLINKING;	/* XXX what is inhibited? */
174 	parms.row_address = ScreenLine(CursorAddress);
175 	parms.column_address = ScreenLineOffset(CursorAddress);
176     }
177 
178     parms.function_id = 0x6b;
179     movetothem(sregs->es, regs->x.di, (char *) &parms, sizeof parms);
180 }
181 
182 /*
183  * Keyboard Services.
184  */
185 
186 
187 static void
188 connect_to_keyboard(regs, sregs)
189 union REGS *regs;
190 struct SREGS *sregs;
191 {
192     ConnectToKeyboardParms parms;
193 
194     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
195 
196     if ((parms.rc != 0) || (parms.function_id != 0)) {
197 	parms.rc = 0x0c;
198     } else if (parms.session_id != 23) {
199 	parms.rc = 0x02;
200     } else if (parms.intercept_options != 0) {
201 	parms.rc = 0x01;
202     } else {
203 	parms.rc = 0;
204 	parms.first_connection_identifier = 0;
205     }
206     parms.function_id = 0x62;
207 
208     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
209 }
210 
211 static void
212 disconnect_from_keyboard(regs, sregs)
213 union REGS *regs;
214 struct SREGS *sregs;
215 {
216     DisconnectFromKeyboardParms parms;
217 
218     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
219 
220     if ((parms.rc != 0) || (parms.function_id != 0)) {
221 	parms.rc = 0x0c;
222     } else if (parms.session_id != 23) {
223 	parms.rc = 0x02;
224     } else if (parms.connectors_task_id != 0) {
225 	parms.rc = 04;			/* XXX */
226     } else {
227 	parms.rc = 0;
228     }
229     parms.function_id = 0x62;
230 
231     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
232 }
233 
234 static void
235 write_keystroke(regs, sregs)
236 union REGS *regs;
237 struct SREGS *sregs;
238 {
239     WriteKeystrokeParms parms;
240 
241     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
242 
243     if ((parms.rc != 0) || (parms.function_id != 0)) {
244 	parms.rc = 0x0c;
245     } else if (parms.session_id != 23) {
246 	parms.rc = 0x02;
247     } else if (parms.connectors_task_id != 0) {
248 	parms.rc = 0x04;
249     } else {
250 	parms.number_of_keys_sent = 0;
251 	parms.rc = 0;
252 	if (parms.options == OPTION_SINGLE_KEYSTROKE) {
253 	    KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry;
254 
255 	    if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) {
256 		parms.rc = 0x10;		/* XXX needs 0x12 too! */
257 	    }
258 	    parms.number_of_keys_sent++;
259 	} else if (parms.options == OPTION_MULTIPLE_KEYSTROKES) {
260 	    KeystrokeList
261 		list,
262 		far *atlist = parms.keystroke_specifier.keystroke_list;
263 	    KeystrokeEntry
264 		entry[10],		/* 10 at a time */
265 		*ourentry,
266 		far *theirentry;
267 	    int
268 		todo;
269 
270 	    movetous((char *)&list, FP_SEG(atlist),
271 				FP_OFF(atlist), sizeof *atlist);
272 	    todo = list.length/2;
273 	    ourentry = entry+(highestof(entry)+1);
274 
275 	    while (todo) {
276 		if (ourentry > &entry[highestof(entry)]) {
277 		    int thistime;
278 
279 		    thistime = todo;
280 		    if (thistime > numberof(entry)) {
281 			thistime = numberof(entry);
282 		    }
283 		    movetous((char *)entry, FP_SEG(theirentry),
284 			    FP_OFF(theirentry), thistime*sizeof *theirentry);
285 		    theirentry += thistime;
286 		    ourentry = entry;
287 		}
288 		if (AcceptKeystroke(ourentry->scancode,
289 						ourentry->shift_state) == 0) {
290 		    parms.rc = 0x10;		/* XXX needs 0x12 too! */
291 		    break;
292 		}
293 		parms.number_of_keys_sent++;
294 		ourentry++;
295 		todo--;
296 	    }
297 	} else {
298 	    parms.rc = 0x01;
299 	}
300     }
301     parms.function_id = 0x62;
302 
303     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
304 /* XXX */
305 }
306 
307 
308 static void
309 disable_input(regs, sregs)
310 union REGS *regs;
311 struct SREGS *sregs;
312 {
313     DisableInputParms parms;
314 
315     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
316 
317     if ((parms.rc != 0) || (parms.function_id != 0)) {
318 	parms.rc = 0x0c;
319     } else if (parms.session_id != 23) {
320 	parms.rc = 0x02;
321     } else if (parms.connectors_task_id != 0) {
322 	parms.rc = 0x04;
323     } else {
324 	SetOiaApiInhibit(&OperatorInformationArea);
325 	parms.rc = 0;
326     }
327     parms.function_id = 0x62;
328 
329     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
330 }
331 
332 static void
333 enable_input(regs, sregs)
334 union REGS *regs;
335 struct SREGS *sregs;
336 {
337     EnableInputParms parms;
338 
339     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
340 
341     if ((parms.rc != 0) || (parms.function_id != 0)) {
342 	parms.rc = 0x0c;
343     } else if (parms.session_id != 23) {
344 	parms.rc = 0x02;
345     } else if (parms.connectors_task_id != 0) {
346 	parms.rc = 0x04;
347     } else {
348 	ResetOiaApiInhibit(&OperatorInformationArea);
349 	parms.rc = 0;
350     }
351     parms.function_id = 0x62;
352 
353     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
354 }
355 
356 /*
357  * Copy Services.
358  */
359 
360 copy_subroutine(target, source, parms, what_is_user)
361 BufferDescriptor *target, *source;
362 CopyStringParms *parms;
363 int what_is_user;
364 #define	USER_IS_TARGET	0
365 #define	USER_IS_SOURCE	1
366 {
367 #define	TARGET_NO_EAB		1
368 #define	SOURCE_NO_EAB		2
369 #define	TARGET_PC		4
370 #define	SOURCE_PC		8
371 #define	NO_FIELD_ATTRIBUTES	16
372     int needtodo = 0;
373     int length;
374     int access_length;
375     char far *input;
376     char far *output;
377     char far *access_pointer;
378 
379     if ((target->characteristics^source->characteristics)
380 		    &CHARACTERISTIC_EAB) {
381 	if (target->characteristics&CHARACTERISTIC_EAB) {
382 	    needtodo |= TARGET_NO_EAB;	/* Need to bump for EAB in target */
383 	} else {
384 	    needtodo |= SOURCE_NO_EAB;	/* Need to bump for EAB in source */
385 	}
386     }
387     if (target->session_type != source->session_type) {
388 	if (target->session_type == TYPE_PC) {
389 	    needtodo |= TARGET_PC;	/* scan codes to PC */
390 	} else {
391 	    needtodo |= SOURCE_PC;	/* PC to scan codes */
392 	}
393     }
394     if ((parms->copy_mode&COPY_MODE_FIELD_ATTRIBUTES) == 0) {
395 	needtodo |= NO_FIELD_ATTRIBUTES;
396     }
397     access_length = length = parms->source_end-source->begin;
398     if (what_is_user == USER_IS_TARGET) {
399 	if (target->characteristics&CHARACTERISTIC_EAB) {
400 	    access_length *= 2;
401 	}
402 	input = (char far *) &Host[source->begin];
403 	access_pointer = target->buffer;
404 	output = access(target->buffer, access_length);
405     } else {
406 	if (source->characteristics&CHARACTERISTIC_EAB) {
407 	    access_length *= 2;
408 	}
409 	access_pointer = source->buffer;
410 	input = access(source->buffer, access_length);
411 	output = (char far *) &Host[target->begin];
412     }
413     while (length--) {
414 	if (needtodo&TARGET_PC) {
415 	    *output++ = disp_asc[*input++];
416 	} else if (needtodo&SOURCE_PC) {
417 	    *output++ = asc_disp[*input++];
418 	} else {
419 	    *output++ = *input++;
420 	}
421 	if (needtodo&TARGET_NO_EAB) {
422 	    *input++;
423 	} else if (needtodo&SOURCE_NO_EAB) {
424 	    *output++ = 0;		/* Should figure out good EAB? */
425 	}
426     }
427     if (what_is_user == USER_IS_TARGET) {
428 	unaccess(target->buffer, access_pointer, access_length);
429     } else {
430 	unaccess(source->buffer, access_pointer, access_length);
431     }
432 }
433 
434 
435 static void
436 copy_string(regs, sregs)
437 union REGS *regs;
438 struct SREGS *sregs;
439 {
440     CopyStringParms parms;
441     BufferDescriptor *target = &parms.target, *source = &parms.source;
442     int length;
443 
444     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
445 
446     if ((parms.rc != 0) || (parms.function_id !=0)) {
447 	parms.rc = 0x0c;
448     } else if (target->session_id == 0) {	/* Target is buffer */
449 	if (source->session_id != 23) {		/* A no-no */
450 	    parms.rc = 0x2;
451 	} else {
452 	    if ((source->characteristics == target->characteristics) &&
453 		    (source->session_type == target->session_type)) {
454 		length = parms.source_end-source->begin;
455 		if (source->characteristics&CHARACTERISTIC_EAB) {
456 		    length *= 2;
457 		}
458 		movetothem( (int) FP_SEG(target->buffer),
459 			(int) FP_OFF(target->buffer),
460 			(char *)&Host[source->begin], length);
461 	    } else {
462 		copy_subroutine(target, source, &parms, USER_IS_TARGET);
463 	    }
464 	}
465     } else if (source->session_id != 0) {
466 	    parms.rc = 0xd;
467     } else {
468 	if ((source->characteristics == target->characteristics) &&
469 		(source->session_type == target->session_type)) {
470 	    length = parms.source_end-source->begin;
471 	    if (source->characteristics&CHARACTERISTIC_EAB) {
472 		length *= 2;
473 	    }
474 	    movetous((char *)&Host[target->begin],
475 			(int) FP_SEG(source->buffer),
476 			(int) FP_OFF(source->buffer), length);
477 	} else {
478 	    copy_subroutine(target, source, &parms, USER_IS_SOURCE);
479 	}
480     }
481     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
482 }
483 /*
484  * Operator Information Area Services.
485  */
486 
487 static void
488 read_oia_group(regs, sregs)
489 union REGS *regs;
490 struct SREGS *sregs;
491 {
492     ReadOiaGroupParms parms;
493 
494     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
495 
496     if ((parms.rc != 0) || (parms.function_id != 0)) {
497 	parms.rc = 0x0c;
498     } else if (parms.session_id != 23) {
499 	parms.rc = 0x02;
500     } else {
501 	int group = parms.oia_group_number;
502 	char *from;
503 	int size;
504 
505 	if ((group != API_OIA_ALL_GROUPS) &&
506 		((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) {
507 	} else {
508 	    if (group == API_OIA_ALL_GROUPS) {
509 		size = API_OIA_BYTES_ALL_GROUPS;
510 		from = (char *)&OperatorInformationArea;
511 	    } else if (group == API_OIA_INPUT_INHIBITED) {
512 		size = sizeof OperatorInformationArea.input_inhibited;
513 		from = (char *)&OperatorInformationArea.input_inhibited[0];
514 	    } else {
515 		size = 1;
516 		from = ((char *)&OperatorInformationArea)+group;
517 	    }
518 	    movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer),
519 			from, size);
520 	}
521     }
522     parms.function_id = 0x6d;
523     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
524 }
525 
526 static void
527 unknown_op(regs, sregs)
528 union REGS *regs;
529 struct SREGS *sregs;
530 {
531     regs->h.ch = 0x12;
532     regs->h.cl = 0x05;
533 }
534 
535 
536 handle_api(regs, sregs)
537 union REGS *regs;
538 struct SREGS *sregs;
539 {
540     if (regs->h.ah == NAME_RESOLUTION) {
541 	name_resolution(regs, sregs);
542     } else if (regs->h.ah != 0x09) {
543 	regs->h.ch = 0x12;
544 	regs->h.cl = 0x0f;		/* XXX Invalid environmental access */
545     } else if (regs->x.bx != 0x8020) {
546 	regs->h.ch = 0x12;
547 	regs->h.cl = 0x08;		/* XXX Invalid wait specified */
548     } else if (regs->h.ch != 0) {
549 	regs->x.cx = 0x1206;		/* XXX Invalid priority */
550     } else {
551 	switch (regs->x.dx) {
552 	case GATE_SESSMGR:
553 	    switch (regs->h.al) {
554 	    case QUERY_SESSION_ID:
555 		if (regs->h.cl != 0) {
556 		    regs->x.cx = 0x1206;
557 		} else {
558 		    regs->x.cx = 0x1200;
559 		    query_session_id(regs, sregs);
560 		}
561 		break;
562 	    case QUERY_SESSION_PARAMETERS:
563 		if (regs->h.cl != 0) {
564 		    regs->x.cx = 0x1206;
565 		} else {
566 		    regs->x.cx = 0x1200;
567 		    query_session_parameters(regs, sregs);
568 		}
569 		break;
570 	    case QUERY_SESSION_CURSOR:
571 		if (regs->h.cl != 0xff) {
572 		    regs->x.cx = 0x1206;
573 		} else {
574 		    regs->x.cx = 0x1200;
575 		    query_session_cursor(regs, sregs);
576 		}
577 		break;
578 	    default:
579 		unknown_op(regs, sregs);
580 		break;
581 	    }
582 	    break;
583 	case GATE_KEYBOARD:
584 	    if (regs->h.cl != 00) {
585 		regs->x.cx = 0x1206;
586 	    } else {
587 		regs->x.cx = 0x1200;
588 		switch (regs->h.al) {
589 		case CONNECT_TO_KEYBOARD:
590 		    connect_to_keyboard(regs, sregs);
591 		    break;
592 		case DISABLE_INPUT:
593 		    disable_input(regs, sregs);
594 		    break;
595 		case WRITE_KEYSTROKE:
596 		    write_keystroke(regs, sregs);
597 		    break;
598 		case ENABLE_INPUT:
599 		    enable_input(regs, sregs);
600 		    break;
601 		case DISCONNECT_FROM_KEYBOARD:
602 		    disconnect_from_keyboard(regs, sregs);
603 		    break;
604 		default:
605 		    unknown_op(regs, sregs);
606 		    break;
607 		}
608 	    }
609 	    break;
610 	case GATE_COPY:
611 	    if (regs->h.cl != 0xff) {
612 		regs->x.cx = 0x1206;
613 	    } else {
614 		regs->x.cx = 0x1200;
615 		switch (regs->h.al) {
616 		case COPY_STRING:
617 		    copy_string(regs, sregs);
618 		    break;
619 		default:
620 		    unknown_op(regs, sregs);
621 		    break;
622 		}
623 	    }
624 	    break;
625 	case GATE_OIAM:
626 	    if (regs->h.cl != 0xff) {
627 		regs->x.cx = 0x1206;
628 	    } else {
629 		regs->x.cx = 0x1200;
630 		switch (regs->h.al) {
631 		case READ_OIA_GROUP:
632 		    read_oia_group(regs, sregs);
633 		    break;
634 		default:
635 		    unknown_op(regs, sregs);
636 		    break;
637 		}
638 	    }
639 	    break;
640 	default:
641 	    regs->h.ch = 0x12;
642 	    regs->h.cl = 0x34;		/* Invalid GATE entry */
643 	    break;
644 	}
645     }
646 }
647