Interface to Mac Communications Toolbox (only Connection Manager for
now)
diff --git a/Mac/Modules/ctbmodule.c b/Mac/Modules/ctbmodule.c
new file mode 100644
index 0000000..52009a0
--- /dev/null
+++ b/Mac/Modules/ctbmodule.c
@@ -0,0 +1,585 @@
+/***********************************************************
+Copyright 1991, 1992, 1993, 1994 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 "allobjects.h"
+#include "modsupport.h"		/* For getargs() etc. */
+
+#include <stdio.h>
+#include <CommResources.h>
+#include <Connections.h>
+#include <ToolUtils.h>
+#include <OSUtils.h>
+/* #include <pascal.h> */
+#ifndef __MWERKS__
+#define ConnectionCompletionUPP ProcPtr
+#define ConnectionChooseIdleUPP ProcPtr
+#define NewConnectionCompletionProc(x) (x)
+#define NewConnectionChooseIdleProc(x) (x)
+#endif
+
+#define 	_UnimplementedToolTrap	0xA89F
+#define 	_CommToolboxTrap		0x8B
+#define 	_UnimplementedOSTrap	0x9F
+
+extern object *PyErr_Mac(object *,int);
+
+static object *ErrorObject;
+
+typedef struct {
+	OB_HEAD
+	ConnHandle hdl;		/* The handle to the connection */
+	object *callback;	/* Python callback routine */
+	int has_callback;	/* True if callback not None */
+	int err;			/* Error to pass to the callback */
+} ctbcmobject;
+
+staticforward typeobject 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) ) {
+		err_setstr(ErrorObject, "CTB not available");
+		return 0;
+	}
+	if ( (err=InitCTBUtilities()) ) {
+		PyErr_Mac(ErrorObject, (int)err);
+		return 0;
+	}
+	if ( (err=InitCRM()) ) {
+		PyErr_Mac(ErrorObject, (int)err);
+		return 0;
+	}
+	if ( (err=InitCM()) ) {
+		PyErr_Mac(ErrorObject, (int)err);
+		return 0;
+	}
+	initialized = 1;
+	return 1;
+}
+
+static int
+ctbcm_pycallback(arg)
+	void *arg;
+{
+	ctbcmobject *self = (ctbcmobject *)arg;
+	object *args, *rv;
+	
+	if ( !self->has_callback )    /* It could have been removed in the meantime */
+		return 0;
+	args = mkvalue("(i)", self->err);
+	rv = call_object(self->callback, args);
+	DECREF(args);
+	if( rv == NULL )
+		return -1;
+	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)
+	object *arg;
+{
+	ctbcmobject *self;
+	self = NEWOBJ(ctbcmobject, &ctbcmtype);
+	if (self == NULL)
+		return NULL;
+	self->hdl = NULL;
+	INCREF(None);
+	self->callback = 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;
+	}
+	DEL(self);
+}
+
+static object *
+ctbcm_open(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	long timeout;
+	OSErr err;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(args, "l", &timeout))
+		return NULL;
+	if ( (err=CMOpen(self->hdl, self->has_callback, cb_upp, timeout)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_listen(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	long timeout;
+	OSErr err;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(args, "l", &timeout))
+		return NULL;
+	if ( (err=CMListen(self->hdl,self->has_callback, cb_upp, timeout)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_accept(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	int accept;
+	OSErr err;
+	
+	if (!getargs(args, "i", &accept))
+		return NULL;
+	if ( (err=CMAccept(self->hdl, accept)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_close(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	int now;
+	long timeout;
+	OSErr err;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(args, "(li)", &timeout, &now))
+		return NULL;
+	if ( (err=CMClose(self->hdl, self->has_callback, cb_upp, timeout, now)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_read(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	long timeout, len;
+	int chan;
+	CMFlags flags;
+	OSErr err;
+	object *rv;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(args, "(lil)", &len, &chan, &timeout))
+		return NULL;
+	if ((rv=newsizedstringobject(NULL, len)) == NULL)
+		return NULL;
+	if ((err=CMRead(self->hdl, (Ptr)getstringvalue(rv), &len, (CMChannel)chan,
+				self->has_callback, cb_upp, timeout, &flags)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	resizestring(&rv, len);
+	return mkvalue("(Oi)", rv, (int)flags);
+}
+
+static object *
+ctbcm_write(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	long timeout, len;
+	int chan, ilen, flags;
+	OSErr err;
+	char *buf;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(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)
+		return PyErr_Mac(ErrorObject, (int)err);
+	return newintobject((int)len);
+}
+
+static object *
+ctbcm_status(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	CMBufferSizes sizes;
+	CMStatFlags flags;
+	OSErr err;
+	object *rv;
+	
+	if (!getnoarg(args))
+		return NULL;
+	if ((err=CMStatus(self->hdl, sizes, &flags)) < 0)
+		return PyErr_Mac(ErrorObject, (int)err);
+	rv = mkvalue("(llllll)", sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], sizes[5]);
+	if ( rv == NULL )
+		return NULL;
+	return mkvalue("(Ol)", rv, (long)flags);
+}
+
+static object *
+ctbcm_getconfig(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	char *rv;
+
+	if (!getnoarg(args))
+		return NULL;
+	if ((rv=(char *)CMGetConfig(self->hdl)) == NULL ) {
+		err_setstr(ErrorObject, "CMGetConfig failed");
+		return NULL;
+	}
+	return newstringobject(rv);
+}
+
+static object *
+ctbcm_setconfig(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	char *cfg;
+	OSErr err;
+	
+	if (!getargs(args, "s", &cfg))
+		return NULL;
+	if ((err=CMSetConfig(self->hdl, (Ptr)cfg)) < 0)
+		return PyErr_Mac(ErrorObject, err);
+	return newintobject((int)err);
+}
+
+static object *
+ctbcm_choose(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	int rv;
+	Point pt;
+
+	if (!getnoarg(args))
+		return NULL;
+	pt.v = 40;
+	pt.h = 40;
+	rv=CMChoose(&self->hdl, pt, (ConnectionChooseIdleUPP)0);
+	return newintobject(rv);
+}
+
+static object *
+ctbcm_idle(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+	CMIdle(self->hdl);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_abort(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+	CMAbort(self->hdl);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_reset(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+	CMReset(self->hdl);
+	INCREF(None);
+	return None;
+}
+
+static object *
+ctbcm_break(self, args)
+	ctbcmobject *self;
+	object *args;
+{
+	long duration;
+	ConnectionCompletionUPP cb_upp = NewConnectionCompletionProc(ctbcm_ctbcallback);
+	
+	if (!getargs(args, "l", &duration))
+		return NULL;
+	CMBreak(self->hdl, duration,self->has_callback, cb_upp);
+	INCREF(None);
+	return None;
+}
+
+static struct methodlist ctbcm_methods[] = {
+	{"Open",		(method)ctbcm_open},
+	{"Close",		(method)ctbcm_close},
+	{"Read",		(method)ctbcm_read},
+	{"Write",		(method)ctbcm_write},
+	{"Status",		(method)ctbcm_status},
+	{"GetConfig",	(method)ctbcm_getconfig},
+	{"SetConfig",	(method)ctbcm_setconfig},
+	{"Choose",		(method)ctbcm_choose},
+	{"Idle",		(method)ctbcm_idle},
+	{"Listen",		(method)ctbcm_listen},
+	{"Accept",		(method)ctbcm_accept},
+	{"Abort",		(method)ctbcm_abort},
+	{"Reset",		(method)ctbcm_reset},
+	{"Break",		(method)ctbcm_break},
+	{NULL,		NULL}		/* sentinel */
+};
+
+static object *
+ctbcm_getattr(self, name)
+	ctbcmobject *self;
+	char *name;
+{
+	if ( strcmp(name, "callback") == 0 ) {
+		INCREF(self->callback);
+		return self->callback;
+	}
+	return findmethod(ctbcm_methods, (object *)self, name);
+}
+
+static int
+ctbcm_setattr(self, name, v)
+	ctbcmobject *self;
+	char *name;
+	object *v;
+{
+	if ( strcmp(name, "callback") != 0 ) {
+		err_setstr(AttributeError, "ctbcm objects have callback attr only");
+		return -1;
+	}
+	if ( v == NULL ) {
+		v = None;
+	}
+	INCREF(v);	/* XXXX Must I do this? */
+	self->callback = v;
+	self->has_callback = (v != None);
+	return 0;
+}
+
+static typeobject ctbcmtype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"ctbcm",			/*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 object *
+ctb_cmnew(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	int strlen;
+	object *sizes_obj;
+	char *c_str;
+	unsigned char p_str[255];
+	CMBufferSizes sizes;
+	short procid;
+	ConnHandle hdl;
+	ctbcmobject *rv;
+	
+	if (!getargs(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 == None ) {
+		memset(sizes, '\0', sizeof sizes);
+	} else {
+		if ( !getargs(sizes_obj, "(llllll)", &sizes[0], &sizes[1], &sizes[2],
+						&sizes[3], &sizes[4], &sizes[5]))
+			return NULL;
+	}
+	if ( (procid=CMGetProcID(p_str)) < 0 )
+		return PyErr_Mac(ErrorObject, procid);
+	hdl = CMNew(procid, cmNoMenus|cmQuiet, sizes, 0, 0);
+	if ( hdl == NULL ) {
+		err_setstr(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 (object *)rv;
+}
+
+static object *
+ctb_available(self, args)
+	object *self;
+	object *args;
+{
+	int ok;
+	
+	if (!getnoarg(args))
+		return NULL;
+	ok = initialize_ctb();
+	err_clear();
+	return newintobject(ok);
+}
+
+/* List of functions defined in the module */
+
+static struct methodlist ctb_methods[] = {
+	{"CMNew",		ctb_cmnew},
+	{"available",	ctb_available},
+	{NULL,		NULL}		/* sentinel */
+};
+
+
+/* Initialization function for the module (*must* be called initctb) */
+
+void
+initctb()
+{
+	object *m, *d, *o;
+
+	/* Create the module and add the functions */
+	m = initmodule("ctb", ctb_methods);
+
+	/* Add some symbolic constants to the module */
+	d = getmoduledict(m);
+	
+#define CMCONST(name, value) o = newintobject(value); dictinsert(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 = newstringobject("ctb.error");
+	dictinsert(d, "error", ErrorObject);
+
+	/* Check for errors */
+	if (err_occurred())
+		fatal("can't initialize module ctb");
+}