xref: /csrg-svn/usr.bin/tn3270/ctlr/api.c (revision 31517)
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 #if	defined(unix)
557     } else if (regs->h.ah == PS_OR_OIA_MODIFIED) {
558 	while ((oia_modified == 0) && (ps_modified == 0)) {
559 	    (void) Scheduler(1);
560 	}
561 	oia_modified = ps_modified = 0;
562 #endif	/* defined(unix) */
563     } else if (regs->h.ah != 0x09) {
564 	regs->h.ch = 0x12;
565 	regs->h.cl = 0x0f;		/* XXX Invalid environmental access */
566     } else if (regs->x.bx != 0x8020) {
567 	regs->h.ch = 0x12;
568 	regs->h.cl = 0x08;		/* XXX Invalid wait specified */
569     } else if (regs->h.ch != 0) {
570 	regs->x.cx = 0x1206;		/* XXX Invalid priority */
571     } else {
572 	switch (regs->x.dx) {
573 	case GATE_SESSMGR:
574 	    switch (regs->h.al) {
575 	    case QUERY_SESSION_ID:
576 		if (regs->h.cl != 0) {
577 		    regs->x.cx = 0x1206;
578 		} else {
579 		    regs->x.cx = 0x1200;
580 		    query_session_id(regs, sregs);
581 		}
582 		break;
583 	    case QUERY_SESSION_PARAMETERS:
584 		if (regs->h.cl != 0) {
585 		    regs->x.cx = 0x1206;
586 		} else {
587 		    regs->x.cx = 0x1200;
588 		    query_session_parameters(regs, sregs);
589 		}
590 		break;
591 	    case QUERY_SESSION_CURSOR:
592 		if (regs->h.cl != 0xff) {
593 		    regs->x.cx = 0x1206;
594 		} else {
595 		    regs->x.cx = 0x1200;
596 		    query_session_cursor(regs, sregs);
597 		}
598 		break;
599 	    default:
600 		unknown_op(regs, sregs);
601 		break;
602 	    }
603 	    break;
604 	case GATE_KEYBOARD:
605 	    if (regs->h.cl != 00) {
606 		regs->x.cx = 0x1206;
607 	    } else {
608 		regs->x.cx = 0x1200;
609 		switch (regs->h.al) {
610 		case CONNECT_TO_KEYBOARD:
611 		    connect_to_keyboard(regs, sregs);
612 		    break;
613 		case DISABLE_INPUT:
614 		    disable_input(regs, sregs);
615 		    break;
616 		case WRITE_KEYSTROKE:
617 		    write_keystroke(regs, sregs);
618 		    break;
619 		case ENABLE_INPUT:
620 		    enable_input(regs, sregs);
621 		    break;
622 		case DISCONNECT_FROM_KEYBOARD:
623 		    disconnect_from_keyboard(regs, sregs);
624 		    break;
625 		default:
626 		    unknown_op(regs, sregs);
627 		    break;
628 		}
629 	    }
630 	    break;
631 	case GATE_COPY:
632 	    if (regs->h.cl != 0xff) {
633 		regs->x.cx = 0x1206;
634 	    } else {
635 		regs->x.cx = 0x1200;
636 		switch (regs->h.al) {
637 		case COPY_STRING:
638 		    copy_string(regs, sregs);
639 		    break;
640 		default:
641 		    unknown_op(regs, sregs);
642 		    break;
643 		}
644 	    }
645 	    break;
646 	case GATE_OIAM:
647 	    if (regs->h.cl != 0xff) {
648 		regs->x.cx = 0x1206;
649 	    } else {
650 		regs->x.cx = 0x1200;
651 		switch (regs->h.al) {
652 		case READ_OIA_GROUP:
653 		    read_oia_group(regs, sregs);
654 		    break;
655 		default:
656 		    unknown_op(regs, sregs);
657 		    break;
658 		}
659 	    }
660 	    break;
661 	default:
662 	    regs->h.ch = 0x12;
663 	    regs->h.cl = 0x34;		/* Invalid GATE entry */
664 	    break;
665 	}
666     }
667 }
668