/*********************************************************** Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* Note: This file is partially converted to the new naming standard */ /* ctbcm objects */ #include "Python.h" #include "macglue.h" #include #include #include #include #ifndef HAVE_UNIVERSAL_HEADERS #define ConnectionCompletionUPP ProcPtr #define ConnectionChooseIdleUPP ProcPtr #define NewConnectionCompletionProc(x) (x) #define NewConnectionChooseIdleProc(x) (x) #endif #define _UnimplementedToolTrap 0xA89F #define _CommToolboxTrap 0x8B #define _UnimplementedOSTrap 0x9F static char *errornames[] = { "No Error", "Rejected", /* 1 */ "Failed", /* 2 */ "Timeout", /* 3 */ "Not Open", /* 4 */ "Not Closed", /* 5 */ "No Request Pending", /* 6 */ "Not Supported", /* 7 */ "No Tools", /* 8 */ "User Cancel", /* 9 */ "Error 10", /* 10 */ "Unknown Error", /* 11 */ #define MAX_POS_ERROR 11 }; extern PyObject *PyErr_Mac(PyObject *,int); static PyObject * PyCtb_Error(PyObject *errobj, int errcode) { if ( errcode > 0 && errcode <= MAX_POS_ERROR ) { PyErr_SetString(errobj, errornames[errcode]); return NULL; } else { return PyErr_Mac(errobj, errcode); } } static PyObject *ErrorObject; typedef struct { PyObject_HEAD ConnHandle hdl; /* The handle to the connection */ PyObject *callback; /* Python callback routine */ int has_callback; /* True if callback not None */ int err; /* Error to pass to the callback */ } ctbcmobject; staticforward PyTypeObject ctbcmtype; #define is_ctbcmobject(v) ((v)->ob_type == &ctbcmtype) static TrapAvailable(short tNumber, TrapType tType) { short unImplemented; if (tType == OSTrap) unImplemented = _UnimplementedOSTrap; else unImplemented = _UnimplementedToolTrap; return NGetTrapAddress(tNumber, tType) != NGetTrapAddress(unImplemented, tType); } static initialize_ctb() { OSErr err; static initialized = -1; if ( initialized >= 0 ) return initialized; initialized = 0; if ( !TrapAvailable(_CommToolboxTrap, OSTrap) ) { PyErr_SetString(ErrorObject, "CTB not available"); return 0; } if ( (err=InitCTBUtilities()) ) { PyCtb_Error(ErrorObject, (int)err); return 0; } if ( (err=InitCRM()) ) { PyCtb_Error(ErrorObject, (int)err); return 0; } if ( (err=InitCM()) ) { PyCtb_Error(ErrorObject, (int)err); return 0; } initialized = 1; return 1; } static int ctbcm_pycallback(arg) void *arg; { ctbcmobject *self = (ctbcmobject *)arg; PyObject *args, *rv; if ( !self->has_callback ) /* It could have been removed in the meantime */ return 0; args = Py_BuildValue("(i)", self->err); rv = PyEval_CallObject(self->callback, args); Py_DECREF(args); if( rv == NULL ) return -1; Py_DECREF(rv); return 0; } /*DBG*/int ncallback; static pascal void ctbcm_ctbcallback(hconn) ConnHandle hconn; { ctbcmobject *self; /* XXXX Do I have to do the A5 mumbo-jumbo? */ ncallback++; /*DBG*/ self = (ctbcmobject *)CMGetUserData(hconn); self->err = (int)((*hconn)->errCode); Py_AddPendingCall(ctbcm_pycallback, (void *)self); } static ctbcmobject * newctbcmobject(arg) PyObject *arg; { ctbcmobject *self; self = PyObject_NEW(ctbcmobject, &ctbcmtype); if (self == NULL) return NULL; self->hdl = NULL; Py_INCREF(Py_None); self->callback = Py_None; self->has_callback = 0; return self; } /* ctbcm methods */ static void ctbcm_dealloc(self) ctbcmobject *self; { if ( self->hdl ) { (void)CMClose(self->hdl, 0, (ConnectionCompletionUPP)0, 0, 1); /*XXXX Is this safe? */ CMDispose(self->hdl); self->hdl = NULL; } PyMem_DEL(self); } static PyObject * ctbcm_open(self, args) ctbcmobject *self; PyObject *args; { long timeout; OSErr err; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "l", &timeout)) return NULL; if ( (err=CMOpen(self->hdl, self->has_callback, cb_upp, timeout)) != 0) return PyCtb_Error(ErrorObject, (int)err); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_listen(self, args) ctbcmobject *self; PyObject *args; { long timeout; OSErr err; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "l", &timeout)) return NULL; if ( (err=CMListen(self->hdl,self->has_callback, cb_upp, timeout)) != 0) return PyCtb_Error(ErrorObject, (int)err); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_accept(self, args) ctbcmobject *self; PyObject *args; { int accept; OSErr err; if (!PyArg_Parse(args, "i", &accept)) return NULL; if ( (err=CMAccept(self->hdl, accept)) != 0) return PyCtb_Error(ErrorObject, (int)err); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_close(self, args) ctbcmobject *self; PyObject *args; { int now; long timeout; OSErr err; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "(li)", &timeout, &now)) return NULL; if ( (err=CMClose(self->hdl, self->has_callback, cb_upp, timeout, now)) != 0) return PyCtb_Error(ErrorObject, (int)err); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_read(self, args) ctbcmobject *self; PyObject *args; { long timeout, len; int chan; CMFlags flags; OSErr err; PyObject *rv, *rrv; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "(lil)", &len, &chan, &timeout)) return NULL; if ((rv=PyString_FromStringAndSize(NULL, len)) == NULL) return NULL; if ((err=CMRead(self->hdl, (Ptr)PyString_AsString(rv), &len, (CMChannel)chan, self->has_callback, cb_upp, timeout, &flags)) != 0 && err != cmTimeOut) return PyCtb_Error(ErrorObject, (int)err); _PyString_Resize(&rv, len); rrv = Py_BuildValue("(Oi)", rv, (int)flags); Py_DECREF(rv); return rrv; } static PyObject * ctbcm_write(self, args) ctbcmobject *self; PyObject *args; { long timeout, len; int chan, ilen, flags; OSErr err; char *buf; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "(s#ili)", &buf, &ilen, &chan, &timeout, &flags)) return NULL; len = ilen; if ((err=CMWrite(self->hdl, (Ptr)buf, &len, (CMChannel)chan, self->has_callback, cb_upp, timeout, (CMFlags)flags)) != 0 && err != cmTimeOut) return PyCtb_Error(ErrorObject, (int)err); return PyInt_FromLong((int)len); } static PyObject * ctbcm_status(self, args) ctbcmobject *self; PyObject *args; { CMBufferSizes sizes; CMStatFlags flags; OSErr err; PyObject *rv, *rrv; if (!PyArg_NoArgs(args)) return NULL; if ((err=CMStatus(self->hdl, sizes, &flags)) != 0) return PyCtb_Error(ErrorObject, (int)err); rv = Py_BuildValue("(llllll)", sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], sizes[5]); if ( rv == NULL ) return NULL; rrv = Py_BuildValue("(Ol)", rv, (long)flags); Py_DECREF(rv); return rrv; } static PyObject * ctbcm_getconfig(self, args) ctbcmobject *self; PyObject *args; { char *rv; if (!PyArg_NoArgs(args)) return NULL; if ((rv=(char *)CMGetConfig(self->hdl)) == NULL ) { PyErr_SetString(ErrorObject, "CMGetConfig failed"); return NULL; } return PyString_FromString(rv); } static PyObject * ctbcm_setconfig(self, args) ctbcmobject *self; PyObject *args; { char *cfg; short rv; if (!PyArg_Parse(args, "s", &cfg)) return NULL; rv=CMSetConfig(self->hdl, (Ptr)cfg); return PyInt_FromLong((long)rv); } static PyObject * ctbcm_choose(self, args) ctbcmobject *self; PyObject *args; { int rv; Point pt; if (!PyArg_NoArgs(args)) return NULL; pt.v = 40; pt.h = 40; rv=CMChoose(&self->hdl, pt, (ConnectionChooseIdleUPP)0); return PyInt_FromLong(rv); } static PyObject * ctbcm_idle(self, args) ctbcmobject *self; PyObject *args; { if (!PyArg_NoArgs(args)) return NULL; CMIdle(self->hdl); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_abort(self, args) ctbcmobject *self; PyObject *args; { if (!PyArg_NoArgs(args)) return NULL; CMAbort(self->hdl); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_reset(self, args) ctbcmobject *self; PyObject *args; { if (!PyArg_NoArgs(args)) return NULL; CMReset(self->hdl); Py_INCREF(Py_None); return Py_None; } static PyObject * ctbcm_break(self, args) ctbcmobject *self; PyObject *args; { long duration; ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback); if (!PyArg_Parse(args, "l", &duration)) return NULL; CMBreak(self->hdl, duration,self->has_callback, cb_upp); Py_INCREF(Py_None); return Py_None; } static struct PyMethodDef ctbcm_methods[] = { {"Open", (PyCFunction)ctbcm_open}, {"Close", (PyCFunction)ctbcm_close}, {"Read", (PyCFunction)ctbcm_read}, {"Write", (PyCFunction)ctbcm_write}, {"Status", (PyCFunction)ctbcm_status}, {"GetConfig", (PyCFunction)ctbcm_getconfig}, {"SetConfig", (PyCFunction)ctbcm_setconfig}, {"Choose", (PyCFunction)ctbcm_choose}, {"Idle", (PyCFunction)ctbcm_idle}, {"Listen", (PyCFunction)ctbcm_listen}, {"Accept", (PyCFunction)ctbcm_accept}, {"Abort", (PyCFunction)ctbcm_abort}, {"Reset", (PyCFunction)ctbcm_reset}, {"Break", (PyCFunction)ctbcm_break}, {NULL, NULL} /* sentinel */ }; static PyObject * ctbcm_getattr(self, name) ctbcmobject *self; char *name; { if ( strcmp(name, "callback") == 0 ) { Py_INCREF(self->callback); return self->callback; } return Py_FindMethod(ctbcm_methods, (PyObject *)self, name); } static int ctbcm_setattr(self, name, v) ctbcmobject *self; char *name; PyObject *v; { if ( strcmp(name, "callback") != 0 ) { PyErr_SetString(PyExc_AttributeError, "ctbcm objects have callback attr only"); return -1; } if ( v == NULL ) { v = Py_None; } Py_INCREF(v); self->callback = v; self->has_callback = (v != Py_None); return 0; } statichere PyTypeObject ctbcmtype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "CTBConnectionMgr", /*tp_name*/ sizeof(ctbcmobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)ctbcm_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)ctbcm_getattr, /*tp_getattr*/ (setattrfunc)ctbcm_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; /* --------------------------------------------------------------------- */ /* Function of no arguments returning new ctbcm object */ static PyObject * ctb_cmnew(self, args) PyObject *self; /* Not used */ PyObject *args; { int strlen; PyObject *sizes_obj; char *c_str; unsigned char p_str[255]; CMBufferSizes sizes; short procid; ConnHandle hdl; ctbcmobject *rv; if (!PyArg_Parse(args, "(s#O)", &c_str, &strlen, &sizes_obj)) return NULL; strncpy((char *)p_str+1, c_str, strlen); p_str[0] = strlen; if (!initialize_ctb()) return NULL; if ( sizes_obj == Py_None ) { memset(sizes, '\0', sizeof sizes); } else { if ( !PyArg_Parse(sizes_obj, "(llllll)", &sizes[0], &sizes[1], &sizes[2], &sizes[3], &sizes[4], &sizes[5])) return NULL; } if ( (procid=CMGetProcID(p_str)) < 0 ) return PyCtb_Error(ErrorObject, procid); hdl = CMNew(procid, cmNoMenus|cmQuiet, sizes, 0, 0); if ( hdl == NULL ) { PyErr_SetString(ErrorObject, "CMNew failed"); return NULL; } rv = newctbcmobject(args); if ( rv == NULL ) return NULL; /* XXXX Should dispose of hdl */ rv->hdl = hdl; CMSetUserData(hdl, (long)rv); return (PyObject *)rv; } static PyObject * ctb_available(self, args) PyObject *self; PyObject *args; { int ok; if (!PyArg_NoArgs(args)) return NULL; ok = initialize_ctb(); PyErr_Clear(); return PyInt_FromLong(ok); } /* List of functions defined in the module */ static struct PyMethodDef ctb_methods[] = { {"CMNew", ctb_cmnew}, {"available", ctb_available}, {NULL, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called initctb) */ void initctb() { PyObject *m, *d, *o; /* Create the module and add the functions */ m = Py_InitModule("ctb", ctb_methods); /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); #define CMCONST(name, value) o = PyInt_FromLong(value); PyDict_SetItemString(d, name, o) CMCONST("cmData", 1); CMCONST("cmCntl", 2); CMCONST("cmAttn", 3); CMCONST("cmFlagsEOM", 1); CMCONST("chooseDisaster", -2); CMCONST("chooseFailed", -1); CMCONST("chooseAborted", 0); CMCONST("chooseOKMinor", 1); CMCONST("chooseOKMajor", 2); CMCONST("chooseCancel", 3); CMCONST("cmStatusOpening", 1); CMCONST("cmStatusOpen", 2); CMCONST("cmStatusClosing", 4); CMCONST("cmStatusDataAvail", 8); CMCONST("cmStatusCntlAvail", 0x10); CMCONST("cmStatusAttnAvail", 0x20); CMCONST("cmStatusDRPend", 0x40); CMCONST("cmStatusDWPend", 0x80); CMCONST("cmStatusCWPend", 0x100); CMCONST("cmStatusCWPend", 0x200); CMCONST("cmStatusARPend", 0x400); CMCONST("cmStatusAWPend", 0x800); CMCONST("cmStatusBreakPending", 0x1000); CMCONST("cmStatusListenPend", 0x2000); CMCONST("cmStatusIncomingCallPresent", 0x4000); ErrorObject = PyString_FromString("ctb.error"); PyDict_SetItemString(d, "error", ErrorObject); ctbcmtype.ob_type = &PyType_Type; Py_INCREF(&ctbcmtype); PyDict_SetItemString(d, "CTBConnectionMgrType", (PyObject *)&ctbcmtype); /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("can't initialize module ctb"); }