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