xref: /csrg-svn/usr.bin/tn3270/ctlr/api.c (revision 31470)
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)	(foo)
29 #define	unaccess_api(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 #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 copy_subroutine(target, source, parms, what_is_user)
359 BufferDescriptor *target, *source;
360 CopyStringParms *parms;
361 int what_is_user;
362 #define	USER_IS_TARGET	0
363 #define	USER_IS_SOURCE	1
364 {
365 #define	TARGET_NO_EAB		1
366 #define	SOURCE_NO_EAB		2
367 #define	TARGET_PC		4
368 #define	SOURCE_PC		8
369 #define	NO_FIELD_ATTRIBUTES	16
370     int needtodo = 0;
371     int length;
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 = parms->source_end-source->begin;
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);
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);
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);
427     } else {
428 	unaccess_api(source->buffer, access_pointer, access_length);
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     if ((parms.rc != 0) || (parms.function_id !=0)) {
445 	parms.rc = 0x0c;
446     } else if (target->session_id == 0) {	/* Target is buffer */
447 	if (source->session_id != 23) {		/* A no-no */
448 	    parms.rc = 0x2;
449 	} else {
450 	    if ((source->characteristics == target->characteristics) &&
451 		    (source->session_type == target->session_type)) {
452 		length = parms.source_end-source->begin;
453 		if (source->characteristics&CHARACTERISTIC_EAB) {
454 		    length *= 2;
455 		}
456 		movetothem( (int) FP_SEG(target->buffer),
457 			(int) FP_OFF(target->buffer),
458 			(char *)&Host[source->begin], length);
459 	    } else {
460 		copy_subroutine(target, source, &parms, USER_IS_TARGET);
461 	    }
462 	}
463     } else if (source->session_id != 0) {
464 	    parms.rc = 0xd;
465     } else {
466 	if ((source->characteristics == target->characteristics) &&
467 		(source->session_type == target->session_type)) {
468 	    length = parms.source_end-source->begin;
469 	    if (source->characteristics&CHARACTERISTIC_EAB) {
470 		length *= 2;
471 	    }
472 	    movetous((char *)&Host[target->begin],
473 			(int) FP_SEG(source->buffer),
474 			(int) FP_OFF(source->buffer), length);
475 	} else {
476 	    copy_subroutine(target, source, &parms, USER_IS_SOURCE);
477 	}
478     }
479     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
480 }
481 /*
482  * Operator Information Area Services.
483  */
484 
485 static void
486 read_oia_group(regs, sregs)
487 union REGS *regs;
488 struct SREGS *sregs;
489 {
490     ReadOiaGroupParms parms;
491 
492     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
493 
494     if ((parms.rc != 0) || (parms.function_id != 0)) {
495 	parms.rc = 0x0c;
496     } else if (parms.session_id != 23) {
497 	parms.rc = 0x02;
498     } else {
499 	int group = parms.oia_group_number;
500 	char *from;
501 	int size;
502 
503 	if ((group != API_OIA_ALL_GROUPS) &&
504 		((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) {
505 	} else {
506 	    if (group == API_OIA_ALL_GROUPS) {
507 		size = API_OIA_BYTES_ALL_GROUPS;
508 		from = (char *)&OperatorInformationArea;
509 	    } else if (group == API_OIA_INPUT_INHIBITED) {
510 		size = sizeof OperatorInformationArea.input_inhibited;
511 		from = (char *)&OperatorInformationArea.input_inhibited[0];
512 	    } else {
513 		size = 1;
514 		from = ((char *)&OperatorInformationArea)+group;
515 	    }
516 	    movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer),
517 			from, size);
518 	}
519     }
520     parms.function_id = 0x6d;
521     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
522 }
523 
524 static void
525 unknown_op(regs, sregs)
526 union REGS *regs;
527 struct SREGS *sregs;
528 {
529     regs->h.ch = 0x12;
530     regs->h.cl = 0x05;
531 }
532 
533 
534 handle_api(regs, sregs)
535 union REGS *regs;
536 struct SREGS *sregs;
537 {
538     if (regs->h.ah == NAME_RESOLUTION) {
539 	name_resolution(regs, sregs);
540     } else if (regs->h.ah != 0x09) {
541 	regs->h.ch = 0x12;
542 	regs->h.cl = 0x0f;		/* XXX Invalid environmental access */
543     } else if (regs->x.bx != 0x8020) {
544 	regs->h.ch = 0x12;
545 	regs->h.cl = 0x08;		/* XXX Invalid wait specified */
546     } else if (regs->h.ch != 0) {
547 	regs->x.cx = 0x1206;		/* XXX Invalid priority */
548     } else {
549 	switch (regs->x.dx) {
550 	case GATE_SESSMGR:
551 	    switch (regs->h.al) {
552 	    case QUERY_SESSION_ID:
553 		if (regs->h.cl != 0) {
554 		    regs->x.cx = 0x1206;
555 		} else {
556 		    regs->x.cx = 0x1200;
557 		    query_session_id(regs, sregs);
558 		}
559 		break;
560 	    case QUERY_SESSION_PARAMETERS:
561 		if (regs->h.cl != 0) {
562 		    regs->x.cx = 0x1206;
563 		} else {
564 		    regs->x.cx = 0x1200;
565 		    query_session_parameters(regs, sregs);
566 		}
567 		break;
568 	    case QUERY_SESSION_CURSOR:
569 		if (regs->h.cl != 0xff) {
570 		    regs->x.cx = 0x1206;
571 		} else {
572 		    regs->x.cx = 0x1200;
573 		    query_session_cursor(regs, sregs);
574 		}
575 		break;
576 	    default:
577 		unknown_op(regs, sregs);
578 		break;
579 	    }
580 	    break;
581 	case GATE_KEYBOARD:
582 	    if (regs->h.cl != 00) {
583 		regs->x.cx = 0x1206;
584 	    } else {
585 		regs->x.cx = 0x1200;
586 		switch (regs->h.al) {
587 		case CONNECT_TO_KEYBOARD:
588 		    connect_to_keyboard(regs, sregs);
589 		    break;
590 		case DISABLE_INPUT:
591 		    disable_input(regs, sregs);
592 		    break;
593 		case WRITE_KEYSTROKE:
594 		    write_keystroke(regs, sregs);
595 		    break;
596 		case ENABLE_INPUT:
597 		    enable_input(regs, sregs);
598 		    break;
599 		case DISCONNECT_FROM_KEYBOARD:
600 		    disconnect_from_keyboard(regs, sregs);
601 		    break;
602 		default:
603 		    unknown_op(regs, sregs);
604 		    break;
605 		}
606 	    }
607 	    break;
608 	case GATE_COPY:
609 	    if (regs->h.cl != 0xff) {
610 		regs->x.cx = 0x1206;
611 	    } else {
612 		regs->x.cx = 0x1200;
613 		switch (regs->h.al) {
614 		case COPY_STRING:
615 		    copy_string(regs, sregs);
616 		    break;
617 		default:
618 		    unknown_op(regs, sregs);
619 		    break;
620 		}
621 	    }
622 	    break;
623 	case GATE_OIAM:
624 	    if (regs->h.cl != 0xff) {
625 		regs->x.cx = 0x1206;
626 	    } else {
627 		regs->x.cx = 0x1200;
628 		switch (regs->h.al) {
629 		case READ_OIA_GROUP:
630 		    read_oia_group(regs, sregs);
631 		    break;
632 		default:
633 		    unknown_op(regs, sregs);
634 		    break;
635 		}
636 	    }
637 	    break;
638 	default:
639 	    regs->h.ch = 0x12;
640 	    regs->h.cl = 0x34;		/* Invalid GATE entry */
641 	    break;
642 	}
643     }
644 }
645