/* Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved C COMMUNICATIONS TOOLKIT CAS.C -- Intel/DCA CAS support functions. NOTE: This file must be compiled with PACKED structures. */ #define CCT_DEVELOPMENT #if (defined(CCTW) || defined(_WINDOWS)) #include #endif #include #include #include #include #include #include WORD cas_multiplex_num = 0XCB; /* CAS multiplex number */ struct mclink { struct mclink *next; struct mclink *prev; }; short cas_free_all(CAS *c); short cas_free_all_ftr(void *p); /* LL_APPEND -- Append a node to a linked list in the structure "mclink". Note that node->next is initialized to NULL; Parameters: void **base -- the address of the beginning of the list; void *node -- the address of the node to append; Return Value: 0 -- always 0 in the current implementation; */ short ll_append(void **base, void *node) { struct mclink *p; if (*base == NULL) *base = node; else { p = *base; while (p->next != NULL) p = p->next; p->next = node; } ((struct mclink *)node)->next = NULL; return (0); } short cas_free_all_ftr(void *p) { void *base; if (p == NULL) return (EOF); while (((struct mclink *)p)->next != NULL) { base = p; p = ((struct mclink *)p)->next; memfree(base); } memfree(p); return (0); } /* ISACAS -- Determine installed state of Connection CoProcessor. Returns: 0 -- Not installed; 1 -- Installed; */ short isacas(void) { union REGS regs; install_cas_isr; setwordreg(ax) = (cas_multiplex_num << 8); int86(MULTIPLEX_INT, ®s, ®s); return (setbytereg(al) == 0XFF); } /* CAS_SUBMIT -- Send a task to the connection coprocessor. Return value: event handle or a negative error code. */ short cas_submit(char FAR_ *tcf) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 1; r.ds = FP_SEG(tcf); setwordreg(dx) = FP_OFF(tcf); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* CAS_ABORT_CURRENT_EVENT -- Abort the current connection coprocessor event. Return value: event handle or negative error code. */ short cas_abort_current_event(void) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 2; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_FINDFIRST -- Find first entry in the specified CAS queue. On Entry: status -- type of event to be sought; direction -- search forward or backward; queue -- task, receive, or log. On exit: event_handle-- the handle matching the search criteria; Return value: 0 if successful, else negative; */ short cas_findfirst(short status, short direction, WORD queue, short *event_handle) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 5; setwordreg(cx) = status; setwordreg(dx) = (direction << 8) | queue; int86(MULTIPLEX_INT, ®s, ®s); *event_handle = setwordreg(bx); return (setwordreg(ax)); } /* CAS_FINDNEXT -- Find next entry in the specified CAS queue. On Entry: queue -- task, receive, or log. On exit: event_handle-- the handle matching the search criteria; Return value: 0 if successful, else negative; */ short cas_findnext(WORD queue, short *event_handle) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 6; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); *event_handle = setwordreg(bx); return (setwordreg(ax)); } /* CAS_OPEN -- Open the DOS file associated with the specified event handle. On Entry: event_handle-- specified event; file_num -- receive file number (otherwise ignored); queue -- task, receive, or log. On exit: file_handle -- the DOS file handle matching the search criteria; Return value: 0 if successful, else negative; */ short cas_open(WORD event_handle, WORD file_num, WORD queue, WORD *file_handle) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 7; setwordreg(bx) = event_handle; setwordreg(cx) = file_num; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); *file_handle = setwordreg(bx); return (setwordreg(ax)); } /* CAS_UNLINK -- Delete the DOS file associated with the specified event handle. On Entry: event_handle-- specified event; file_num -- receive file number (otherwise ignored); queue -- task, receive, or log. Return value: 0 if successful, else negative; */ short cas_unlink(WORD event_handle, WORD file_num, WORD queue) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 8; setwordreg(bx) = event_handle; setwordreg(cx) = file_num; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_UNLINKALL -- Delete all DOS files in a queue. On Entry: queue -- task, receive, or log. Return value: 0 if successful, else negative; */ short cas_unlinkall(WORD queue) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 9; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_GET_EVENT_DATE -- Get the date associated with the specified event handle. On Entry: event_handle-- specified event; queue -- task, receive, or log; Return value: 0 if successful, else negative; */ short cas_get_event_date(WORD event_handle, WORD queue, struct cct_date *event_date) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X0A; setwordreg(bx) = event_handle; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); event_date->year = setwordreg(cx); event_date->month = setwordreg(dx) >> 8; event_date->day = setwordreg(dx) & 0XFF; return (setwordreg(ax)); } /* CAS_SET_TASK_DATE -- Set the execute date of a task control file specified by the event handle. On Entry: event_handle-- specified event; event_date -- date task is to execute; Return value: 0 if successful, else negative; */ short cas_set_task_date(WORD event_handle, struct cct_date *event_date) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X0B; setwordreg(bx) = event_handle; setwordreg(cx) = event_date->year; setwordreg(dx) = (event_date->month << 8) | event_date->day; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_GET_EVENT_TIME -- Get the time associated with the specified event handle. On Entry: event_handle-- specified event; queue -- task, receive, or log. event_date -- date task is to execute; Return value: 0 if successful, else negative; */ short cas_get_event_time(WORD event_handle, WORD queue, struct cct_date *event_date) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X0C; setwordreg(bx) = event_handle; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); event_date->hour = setwordreg(cx) >> 8; event_date->minute = setwordreg(cx) & 0XFF; event_date->second = setwordreg(dx) >> 8; return (setwordreg(ax)); } /* CAS_SET_TASK_TIME -- Set the execute time of a task control file specified by the event handle. On Entry: event_handle-- specified event; event_date -- date task is to execute; Return value: 0 if successful, else negative; */ short cas_set_task_time(WORD event_handle, struct cct_date *event_date) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X0D; setwordreg(bx) = event_handle; setwordreg(cx) = (event_date->hour << 8) | event_date->minute; setwordreg(dx) = event_date->second << 8; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_GET_EXTERNAL_DATA_BLOCK -- Get the external data block. On Entry: edb -- 256 byte external data block area; Return value: 0 if successful, else negative; */ short cas_get_external_data_block(char *edb) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 0X0E; r.ds = FP_SEG(edb); setwordreg(dx) = FP_OFF(edb); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* CAS_AUTORECEIVE_STATE -- Get/set the autoreceive state of the hardware. On Entry: func -- function code (0=get, 1=set); rings -- no. of rings before autoanswer; Return value: 0 if successful, else negative; */ short cas_autoreceive_state(WORD func, WORD rings) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X0F; setwordreg(dx) = (rings << 8) | func; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_GET_CES -- return the status of the currently executing event. On Entry: status -- 444 byte status area; On exit: status area is filled with information; Return value: 0 if successful, else negative; */ short cas_get_ces(char *status) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 0X10; r.ds = FP_SEG(status); setwordreg(dx) = FP_OFF(status); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* CAS_GET_QUEUE_STATUS -- return the status of the specfied queue. On Entry: queue -- task, receive, or log. num_ctl -- num_rx -- On exit: count -- current number of Control Files in specified queue; num -- current number of received files (receive queue only); Return value: number of queue changes if successful, else negative; */ short cas_get_queue_status(WORD queue, WORD *num_ctl, WORD *num_rx) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X11; setwordreg(dx) = queue; int86(MULTIPLEX_INT, ®s, ®s); *num_ctl = setwordreg(bx); *num_rx = setwordreg(cx); return (setwordreg(ax)); } /* CAS_GET_HARDWARE_STATUS -- return the status of the hardware. On Entry: status -- 128 byte status area; On exit: status area is filled with information; Return value: 0 if successful, else negative; */ short cas_get_hardware_status(char *status) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 0X12; r.ds = FP_SEG(status); setwordreg(dx) = FP_OFF(status); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* CAS_RUN_DIAGNOSTICS -- Runs a set of diagnostics. On Entry: mode -- start running (0), or report progress (1); Return value: 0 successsful; 040h diagnostics in progress; <0 error code (see manufacturer's specs); */ short cas_run_diagnostics(WORD mode) { union REGS regs; setwordreg(ax) = (cas_multiplex_num << 8) | 0X13; setwordreg(dx) = mode; int86(MULTIPLEX_INT, ®s, ®s); return (setwordreg(ax)); } /* CAS_MOVE_RECEIVED_FILE -- Move a received file to a different directory and give it a new name. On Entry: event_handle -- handle of specified event; num -- received file number; new_name -- new name for file; Return value: 0 if successful, else negative; */ short cas_move_received_file(WORD event_handle, WORD num, char *new_name) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 0X14; setwordreg(bx) = event_handle; setwordreg(cx) = num; r.ds = FP_SEG(new_name); setwordreg(dx) = FP_OFF(new_name); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* CAS_SUBMIT_FILE -- Submit a single file to send. On Entry: status -- pointer to variable length data area; Return value: 0 if successful, else negative; */ short cas_submit_file(char *status) { union REGS regs; struct SREGS r; segread(&r); setwordreg(ax) = (cas_multiplex_num << 8) | 0X15; r.ds = FP_SEG(status); setwordreg(dx) = FP_OFF(status); int86x(MULTIPLEX_INT, ®s, ®s, &r); return (setwordreg(ax)); } /* ================= HIGHER-LEVEL FUNCTIONS BEGIN HERE ===================== */ /* CAS_CREATE_TASK -- Initialize for the Intel Connection CoProcessor. This function must be called prior to use of the Connection CoProcessor. 1) Allocate memory for a structure of type CAS; 2) Allocate memory for CAS_CONTROL_FILE structure; Return value: A pointer to the CAS structure, or NULL if an error occurs. */ CAS *cas_create_task(WORD etype, char *from, char *to, char *num, WORD date, WORD time) { CAS *c = NULL; if (!isacas()) return (NULL); if ((c = (CAS *) memcalloc(1, sizeof(CAS))) != NULL) { if ((c->f = (CAS_CONTROL_FILE *) memcalloc(1, sizeof(CAS_CONTROL_FILE))) != NULL) { c->f->event_type = (char) etype; if (from != NULL) strncpy(c->f->sender, from, 32); if (to != NULL) strncpy(c->f->dest, to, 32); strncpy(c->f->phone_num, num, 47); c->f->event_date = date; c->f->event_time = time; } else { memfree(c); c = NULL; } } return (c); } /* CAS_QUEUE_FILE -- Add a new FTR to the linked list of FTRs for the current task. */ short cas_queue_file(CAS *c, WORD ftype, WORD text_size, char *fpath, WORD increments, WORD pl) { CAS_FILE_TRANSFER_RECORD *ftr, *q; if (c == NULL || c->f == NULL) return (EOF); ftr = memcalloc(1, sizeof(CAS_FILE_TRANSFER_RECORD)); if (ftr == NULL) { cas_free_all(c); c = NULL; return (-2); } ftr->next = NULL; /* INITIALIZE FTR FIELDS */ ftr->ftype = (char) ftype; ftr->text_size = (char) text_size; strncpy(ftr->fpath, fpath, 80); ftr->increments = (char) increments; ftr->pl = (char) pl; c->f->num_files++; /* update count of files to send */ /* ADD AN FTR FOR THIS FILE */ if (c->ftr == NULL) c->ftr = ftr; else { q = c->ftr; while (q->next != NULL) q = q->next; q->next = ftr; } return (0); } /* CAS_SEND_ONE_FILE -- High level function to send a FAX via a CAS device. Return value: 0 -- success; EOF -- CoCo (or its driver) not installed; */ short cas_send_one_file(CAS *c, char *filename, char *to, char *phone_num) { char buffer[255]; if (!isacas()) return (EOF); memset(buffer, 0X0, 255); /* initialize buffer */ if (to == NULL) strcpy(&buffer[6], ""); else strncpy(&buffer[6], to, 32); strncpy(&buffer[38], filename, 80); strncpy(&buffer[118], (phone_num[0] == '\0') ? c->f->phone_num : phone_num, 47); return (cas_submit_file(buffer)); } /* CAS_DEINIT -- Called when all processing finished to free memory allocated for CAS related data structures. */ short cas_deinit(CAS *c) { cas_free_all(c); return (0); } /* CAS_SUBMIT_TASK -- Submit a task (created with CAS_CREATE_TASK) to the CAS device. Return code: EOF -- No task control file image; -2 -- Unable to open Task Control File; -3 -- Error writing CAS Task Control File Image to file; -4 -- Error writing cover text to file; -5 -- Error writing FTR image to file; >0 -- valid handle returned by CAS device; */ short cas_submit_task(CAS *c, char *fname, short mode, char *lpath, char *cover) { short i; CAS_FILE_TRANSFER_RECORD *ftr; WORD len = 0; short ret = 0; if (c->ftr == NULL || c == NULL) return (EOF); /* no files to send */ /* INITIALIZE CONTROL FILE MEMBERS */ c->f->transfer_type = (char) mode; /* transfer type (FAX, file, etc.) */ if (lpath != NULL) strncpy(c->f->lpath, lpath, 80); /* path for logo */ if (cover != NULL) len = strlen(cover); /* compute length of cover page */ if (len) c->f->cover_flag = (char) TRUE; /* flag -- send cover page */ c->f->ftr_offset = (c->f->cover_flag) ? 383 + len + 1 : 383; /* OPEN TASK CONTROL FILE AND WRITE RECORDS TO IT */ if ((c->fh = cct_file_open_(fname, O_CREAT | O_WRONLY | O_BINARY)) == 0) return (-2); /* WRITE CONTROL FILE */ if (cct_file_write_(c->fh, c->f, sizeof(CAS_CONTROL_FILE)) == EOF) ret = -3; else { /* WRITE COVER PAGE */ if (cover != NULL) ret = cct_file_write_(c->fh, cover, len+1); if (ret == EOF) ret = -4; else { /* WRITE FTRS */ for (i= ret = 0, ftr = c->ftr; i < c->f->num_files && !ret; i++) { if (cct_file_write_(c->fh, (char *) ftr + sizeof(void FAR_ *), sizeof(CAS_FILE_TRANSFER_RECORD) - sizeof(void FAR_ *)) == EOF) { ret = -5; break; } ftr = ftr->next; } if (!ret) { cct_file_close_(c->fh); ret = cas_submit(fname); } } } cct_file_close_(c->fh); cas_free_all(c); c = NULL; return (ret); } short cas_free_all(CAS *c) { if (c == NULL) return (EOF); cas_free_all_ftr(c->ftr); /* free file transfer records */ if (c->f != NULL) memfree(c->f); /* free CAS control file */ memfree(c); /* free CAS structure */ return (0); } WORD todosdate(WORD year, WORD month, WORD day) { return(((year - 1980) << 9) | (month << 5) | day); } WORD todostime(WORD hour, WORD minute, WORD sec) { return((hour << 11) | (minute << 5) | (sec >> 1)); } #if defined(CCT_TEST) #include char *logon = "\n\nCopyright (C) Magna Carta Software, Inc. 1989. All Rights Reserved." "\nFAX -- The DOS command line FAX software for the Intel Connection CoProcessor." "\nThis program was created with Magna Carta's \"C Communications Toolkit\"." "\nMagna Carta Software, Inc." "\nP.O. Box 475594" "\nGarland, TX 75047" "\nVoice: (214) 226-6909, FAX: (214) 226-0386, BBS: (214) 226-8088."; short main(int argc, char *argv[]); short main(int argc, char *argv[]) { CAS *c; short ret; fputs(logon, stderr); if (!isacas()) { fputs("Connection Coprocessor Not Installed", stderr); return (EOF); } c = cas_create_task(CAS_SEND, "Me", "The World", "226-0386", todosdate(1990, 4, 9), todostime(3,23,00)); cas_add_file(c, CAS_ASCII, CAS_80_COL, "e:\\cct\\temp1.c", 0, 0); cas_add_file(c, CAS_ASCII, CAS_80_COL, "e:\\cct\\cct51.prj", 0, 0); ret = cas_submit_task(c, "e:\\cct\\temp000.$$$", CAS_200_DPI, "", "Magna Carta Software"); if (ret < 0) fprintf(stderr, "\nError: Class: %#X, Subcode %#X", (-ret >> 8) & 0XFF, -ret & 0XFF); else fprintf(stderr, "\nSuccess: CoCo returned event handle %#X", ret); getch(); return (ret); } #endif