nakedmud-mod/
nakedmud-mod/html/tutorials/
nakedmud-mod/html/tutorials/building_extras/
nakedmud-mod/html/tutorials/c/
nakedmud-mod/html/tutorials/reference/
nakedmud-mod/html/tutorials/scripting/
nakedmud-mod/html/tutorials/scripting_extras/
nakedmud-mod/lib/
nakedmud-mod/lib/help/A/
nakedmud-mod/lib/help/B/
nakedmud-mod/lib/help/C/
nakedmud-mod/lib/help/D/
nakedmud-mod/lib/help/G/
nakedmud-mod/lib/help/H/
nakedmud-mod/lib/help/J/
nakedmud-mod/lib/help/L/
nakedmud-mod/lib/help/M/
nakedmud-mod/lib/help/O/
nakedmud-mod/lib/help/P/
nakedmud-mod/lib/help/R/
nakedmud-mod/lib/help/S/
nakedmud-mod/lib/help/W/
nakedmud-mod/lib/logs/
nakedmud-mod/lib/misc/
nakedmud-mod/lib/players/
nakedmud-mod/lib/pymodules/polc/
nakedmud-mod/lib/txt/
nakedmud-mod/lib/world/
nakedmud-mod/lib/world/zones/examples/
nakedmud-mod/lib/world/zones/examples/mproto/
nakedmud-mod/lib/world/zones/examples/oproto/
nakedmud-mod/lib/world/zones/examples/reset/
nakedmud-mod/lib/world/zones/examples/rproto/
nakedmud-mod/lib/world/zones/examples/trigger/
nakedmud-mod/lib/world/zones/limbo/
nakedmud-mod/lib/world/zones/limbo/room/
nakedmud-mod/lib/world/zones/limbo/rproto/
nakedmud-mod/src/alias/
nakedmud-mod/src/dyn_vars/
nakedmud-mod/src/editor/
nakedmud-mod/src/example_module/
nakedmud-mod/src/help2/
nakedmud-mod/src/set_val/
nakedmud-mod/src/socials/
nakedmud-mod/src/time/
//*****************************************************************************
//
// pysocket.c
//
// Contains a python socket module, and an Socket class that is a python 
// wrapper for NakedMud sockets.
//
//*****************************************************************************

#include "../mud.h"
#include "../utils.h"
#include "../socket.h"
#include "../character.h"

#include "scripts.h"
#include "pyplugs.h"
#include "pyauxiliary.h"
#include "pysocket.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "../editor/editor.h"
#include "script_editor.h"



//*****************************************************************************
// local structures and defines
//*****************************************************************************

// a list of the get/setters on the Exit class
LIST *pysocket_getsetters = NULL;

// a list of the methods on the Exit class
LIST *pysocket_methods = NULL;

typedef struct {
  PyObject_HEAD
  int uid;
} PySocket;



//*****************************************************************************
// allocation, deallocation, initialization, and comparison
//*****************************************************************************
void PySocket_dealloc(PySocket *self) {
  self->ob_type->tp_free((PyObject*)self);
}

PyObject *PySocket_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
    PySocket *self;
    self = (PySocket *)type->tp_alloc(type, 0);
    self->uid = NOTHING;
    return (PyObject *)self;
}

int PySocket_init(PySocket *self, PyObject *args, PyObject *kwds) {
  char *kwlist[] = {"uid", NULL};
  int        uid = NOTHING;

  // get the uid
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &uid)) {
    PyErr_Format(PyExc_TypeError, "Sockets may only be created using an uid");
    return -1;
  }

  // make sure an socket with this name exists
  if(!propertyTableGet(sock_table, uid)) {
    PyErr_Format(PyExc_TypeError, "Socket with uid, %d, does not exist", uid);
    return -1;
  }

  self->uid = uid;
  return 0;
}

int PySocket_compare(PySocket *sock1, PySocket *sock2) {
  if(sock1->uid == sock2->uid)
    return 0;
  else if(sock1->uid < sock2->uid)
    return -1;
  else
    return 1;
}



//*****************************************************************************
// getters and setters for the Socket class
//*****************************************************************************
PyObject *PySocket_getuid(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock != NULL) return Py_BuildValue("i", socketGetUID(sock));
  else             return NULL;
}

PyObject *PySocket_getaccount(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else {
    ACCOUNT_DATA *acc = socketGetAccount(sock);
    if(acc == NULL)
      return Py_BuildValue("O", Py_None);
    return Py_BuildValue("O", accountGetPyFormBorrowed(acc));
  }
}

PyObject *PySocket_getchar(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else {
    CHAR_DATA *ch = socketGetChar(sock);
    // for the time being, we don't return characters without UIDs... like ones
    // that are being created. We have to redo character generation to allow
    // for characters-in-progress to be referenced
    if(ch == NULL || charGetUID(ch) == NOBODY)
      return Py_BuildValue("O", Py_None);
    return Py_BuildValue("O", charGetPyFormBorrowed(ch));
  }
}

PyObject *PySocket_getcmdread(PySocket *self, void *closure) { 
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else {
    return Py_BuildValue("i", socketHasCommand(sock));
  }
}

PyObject *PySocket_get_outbound_text(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else {
    return Py_BuildValue("s", bufferString(socketGetOutbound(sock)));
  } 
}

int PySocket_set_outbound_text(PySocket *self, PyObject *value, void *closure) {
  if(!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, "Outbound text must be in string format.");
    return -1;
  }

  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return -1;
  else {
    bufferClear(socketGetOutbound(sock));
    bufferCat(socketGetOutbound(sock), PyString_AsString(value));
    return 0;
  }
}

PyObject *PySocket_get_can_use(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else
    return Py_BuildValue("i", (socketGetDNSLookupStatus(sock) == TSTATE_DONE ?
			       TRUE : FALSE));
}

PyObject *PySocket_getstate(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else
    return Py_BuildValue("s", socketGetState(sock));
}

PyObject *PySocket_getidletime(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else
    return Py_BuildValue("f", socketGetIdleTime(sock));
}

PyObject *PySocket_gethostname(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  else if(socketGetDNSLookupStatus(sock) == TSTATE_DONE)
    return Py_BuildValue("s", socketGetHostname(sock));
  else
    return Py_BuildValue("s", "unresolved");
}

PyObject *PySocket_getcols(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock != NULL) return Py_BuildValue("i", socketGetCols(sock));
  else             return NULL;
}

PyObject *PySocket_getrows(PySocket *self, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock != NULL) return Py_BuildValue("i", socketGetRows(sock));
  else             return NULL;
}

int PySocket_setcols(PyObject *self, PyObject *value, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return -1;
  else {
    if(value == NULL || value == Py_None)
      socketSetCols(sock, SCREEN_WIDTH);
    else if(PyInt_Check(value))
      socketSetCols(sock, (int)PyInt_AsLong(value));
    else {
      PyErr_Format(PyExc_TypeError,
        "Tried to change socket %d's screen width to an invalid type.",
        socketGetUID(sock));
      return -1;
    }
    
    return 0;
  }
}

int PySocket_setrows(PyObject *self, PyObject *value, void *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return -1;
  else {
    if(value == NULL || value == Py_None)
      socketSetRows(sock, NUM_LINES_PER_PAGE);
    else if(PyInt_Check(value))
      socketSetRows(sock, (int)PyInt_AsLong(value));
    else {
      PyErr_Format(PyExc_TypeError,
        "Tried to change socket %d's screen height to an invalid type.",
        socketGetUID(sock));
      return -1;
    }
    
    return 0;
  }
}

PyObject *PySocket_bust_prompt(PySocket *self, PyObject *closure) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL) {
    PyErr_Format(PyExc_StandardError, "Tried to bust prompt on nonexistent "
		 "socket, %d.", PySocket_AsUid((PyObject *)self));
    return NULL;
  }
  socketBustPrompt(sock);
  return Py_BuildValue("i", 1);
}

PyObject *PySocket_push_ih(PySocket *self, PyObject *args) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  PyObject *handler = NULL;
  PyObject  *prompt = NULL;
  char       *state = NULL;

  if(sock == NULL)
    return NULL;

  if (!PyArg_ParseTuple(args, "OO|s", &handler, &prompt, &state)) {
    PyErr_Format(PyExc_TypeError, "handler and prompt function must "
		 "be supplied.");
    return NULL;
  }

  socketPushPyInputHandler(sock, handler, prompt, (state ? state : ""));
  return Py_BuildValue("i", 1);
}

PyObject *PySocket_pop_ih(PySocket *self) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  socketPopInputHandler(sock);
  return Py_BuildValue("i", 1);
}

PyObject *PySocket_replace_ih(PySocket *self, PyObject *args) {
  PyObject *retval = PySocket_pop_ih(self);
  if(retval == NULL)
    return NULL;
  Py_DECREF(retval);
  retval = PySocket_push_ih(self, args);
  if(retval == NULL)
    return NULL;
  Py_DECREF(retval);
  return Py_BuildValue("i", 1);
}

PyObject *PySocket_send_rraw(PySocket *self, PyObject *value) {
  char *mssg = NULL;
  if (!PyArg_ParseTuple(value, "s", &mssg)) {
    PyErr_Format(PyExc_TypeError, "Sockets may only be sent strings");
    return NULL;
  }

  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock != NULL) {
    raw_to_socket(sock, "%s", mssg);
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_TypeError, 
		 "Tried to send message to nonexistant socket, %d.", 
		 self->uid);
    return NULL;
  }
}

PyObject *PySocket_send_raw(PySocket *self, PyObject *value) {
  char *mssg = NULL;
  if (!PyArg_ParseTuple(value, "s", &mssg)) {
    PyErr_Format(PyExc_TypeError, "Sockets may only be sent strings");
    return NULL;
  }

  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock != NULL) {
    send_to_socket(sock, "%s", mssg);
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_TypeError, 
		 "Tried to send message to nonexistant socket, %d.", 
		 self->uid);
    return NULL;
  }
}

//
// Send a message with Python statements potentially embedded in it. For 
//evaluating 
PyObject *PySocket_send(PyObject *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[ ] = { "mssg", "dict", "newline", NULL };
  SOCKET_DATA *me = NULL;
  char      *text = NULL;
  PyObject  *dict = NULL;
  bool    newline = TRUE;

  if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|Ob", kwlist, 
				  &text, &dict, &newline)) {
    PyErr_Format(PyExc_TypeError, "Invalid arguments supplied to Mudsock.send");
    return NULL;
  }

  // is dict None? set it to NULL for expand_to_char
  if(dict == Py_None)
    dict = NULL;

  // make sure the dictionary is a dictionary
  if(!(dict == NULL || PyDict_Check(dict))) {
    PyErr_Format(PyExc_TypeError, "Mudsock.send expects second argument to be a dict object.");
    return NULL;
  }
  
  // make sure we exist
  if( (me = PySocket_AsSocket(self)) == NULL) {
    PyErr_Format(PyExc_TypeError, "Tried to send nonexistent socket.");
    return NULL;
  }

  if(dict != NULL)
    PyDict_SetItemString(dict, "me", self);

  // build our script environment
  BUFFER   *buf = newBuffer(1);
  bufferCat(buf, text);

  // expand out our dynamic descriptions if we have a dictionary supplied
  if(dict != NULL) {
    PyObject *env = restricted_script_dict();
    PyDict_Update(env, dict);

    // do the expansion
    expand_dynamic_descs_dict(buf, env, get_script_locale());
    Py_XDECREF(env);
  }

  if(newline == TRUE)
    bufferCat(buf, "\r\n");
  text_to_buffer(me, bufferString(buf));

  // garbage collection
  deleteBuffer(buf);
  return Py_BuildValue("");
}

PyObject *PySocket_close(PySocket *self) {
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL)
    return NULL;
  close_socket(sock, FALSE);
  return Py_BuildValue("i", 1);
}

PyObject *PySocket_edit_text(PyObject *self, PyObject *args) {
  PyObject *on_complete = NULL;
  char            *text = NULL;
  char            *type = NULL;
  SOCKET_DATA     *sock = NULL;
  EDITOR        *editor = text_editor;

  if(!PyArg_ParseTuple(args, "sO|s", &text, &on_complete, &type)) {
    PyErr_Format(PyExc_TypeError, "invalid arguments to sock.edit_text");
    return NULL;
  }

  if(!PySocket_Check(self)) {
    PyErr_Format(PyExc_TypeError, "Owner of edit_text not a socket");
    return NULL;
  }
  else if( (sock = PySocket_AsSocket(self)) == NULL) {
    PyErr_Format(PyExc_TypeError, "sock.edit_text called on non-existent socket.");
    return NULL;
  }

  if(type != NULL && compares(type, "script"))
    editor = script_editor;
  
  // begin the editor
  socketStartPyEditorFunc(sock, editor, text, on_complete);
  return Py_BuildValue("O", Py_None);
}



//*****************************************************************************
// methods for the Socket class
//*****************************************************************************

//
// returns the specified piece of auxiliary data from the socket
// if it is a piece of python auxiliary data.
PyObject *PySocket_get_auxiliary(PySocket *self, PyObject *args) {
  char *keyword = NULL;
  if(!PyArg_ParseTuple(args, "s", &keyword)) {
    PyErr_Format(PyExc_TypeError,
		 "getAuxiliary() must be supplied with the name that the "
		 "auxiliary data was installed under!");
    return NULL;
  }

  // make sure we exist
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  if(sock == NULL) {
    PyErr_Format(PyExc_StandardError,
		 "Tried to get auxiliary data for a nonexistant socket.");
    return NULL;
  }

  // make sure the auxiliary data exists
  if(!pyAuxiliaryDataExists(keyword)) {
    PyErr_Format(PyExc_StandardError,
		 "No auxiliary data named '%s' exists!", keyword);
    return NULL;
  }

  PyObject *data = socketGetAuxiliaryData(sock, keyword);
  if(data == NULL)
    data = Py_None;
  PyObject *retval = Py_BuildValue("O", data);
  //  Py_DECREF(data);
  return retval;
}



//*****************************************************************************
// structures to define our methods and classes
//*****************************************************************************
PyTypeObject PySocket_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "mudsock.Mudsock",         /*tp_name*/
    sizeof(PySocket),          /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)PySocket_dealloc,/*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    (cmpfunc)PySocket_compare, /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "Python Socket object",    /* tp_doc */
    0,		               /* tp_traverse */
    0,		               /* tp_clear */
    0,		               /* tp_richcompare */
    0,		               /* tp_weaklistoffset */
    0,		               /* tp_iter */
    0,		               /* tp_iternext */
    0,                         /* tp_methods */
    0,                         /* tp_members */
    0,                         /* tp_getset */ 
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)PySocket_init,   /* tp_init */
    0,                         /* tp_alloc */
    PySocket_new,              /* tp_new */
};



//*****************************************************************************
// methods in the mudsock module
//*****************************************************************************
PyObject *PySocket_all_sockets(PyObject *self) {
  PyObject        *list = PyList_New(0);
  LIST_ITERATOR *sock_i = newListIterator(socket_list);
  SOCKET_DATA     *sock = NULL;
  ITERATE_LIST(sock, sock_i) {
    PyList_Append(list, socketGetPyFormBorrowed(sock));
  } deleteListIterator(sock_i);
  PyObject *retval = Py_BuildValue("O", list);
  Py_DECREF(list);
  return retval;
}

PyMethodDef socket_module_methods[] = {
  { "socket_list", (PyCFunction)PySocket_all_sockets, METH_NOARGS,
    "socket_list()\n\n"
    "Returns a list of all sockets currently connected." },
  {NULL, NULL, 0, NULL}  /* Sentinel */
};



//*****************************************************************************
// implementation of pyexit.h
//*****************************************************************************
void PySocket_addGetSetter(const char *name, void *g, void *s,const char *doc){
  // make sure our list of get/setters is created
  if(pysocket_getsetters == NULL) pysocket_getsetters = newList();

  // make the GetSetter def
  PyGetSetDef *def = calloc(1, sizeof(PyGetSetDef));
  def->name        = strdup(name);
  def->get         = (getter)g;
  def->set         = (setter)s;
  def->doc         = (doc ? strdup(doc) : NULL);
  def->closure     = NULL;
  listPut(pysocket_getsetters, def);
}

void PySocket_addMethod(const char *name, void *f, int flags, const char *doc){
  // make sure our list of methods is created
  if(pysocket_methods == NULL) pysocket_methods = newList();

  // make the Method def
  PyMethodDef *def = calloc(1, sizeof(PyMethodDef));
  def->ml_name     = strdup(name);
  def->ml_meth     = (PyCFunction)f;
  def->ml_flags    = flags;
  def->ml_doc      = (doc ? strdup(doc) : NULL);
  listPut(pysocket_methods, def);
}

// initialize sockets for use. This must be called AFTER 
PyMODINIT_FUNC
init_PySocket(void) {
    PyObject* module = NULL;

    // add all of the basic getsetters
    PySocket_addGetSetter("uid", PySocket_getuid, NULL,
      "The socket's uid. Immutable.");
    PySocket_addGetSetter("account", PySocket_getaccount, NULL,
      "The account currently attached to the socket, or None. Immutable.\n"
      "see mudsys.attach_account_socket for connecting sockets and accounts.");
    PySocket_addGetSetter("character", PySocket_getchar, NULL,
      "The character currently attached to the socket, on None. Immutable.\n"
      "see mudsys.attach_char_socket for connecting characters to account.");
    PySocket_addGetSetter("char", PySocket_getchar, NULL,
       "Alias for mudsock.Mudsock.character");
    PySocket_addGetSetter("ch",   PySocket_getchar, NULL,
       "Alias for mudsock.Mudsock.character.");
    PySocket_addGetSetter("has_input", PySocket_getcmdread, NULL,
       "True or False if the socket has any input pending. Immutable.");
    PySocket_addGetSetter("outbound_text",
       PySocket_get_outbound_text, PySocket_set_outbound_text,
       "The socket's outbound text.");
    PySocket_addGetSetter("can_use", PySocket_get_can_use, NULL,
      "True or False if the socket is ready for use. Socket becomes available\n"
      "after its dns addresss resolves. Immutable.");
    PySocket_addGetSetter("state", PySocket_getstate, NULL,
      "The state that the socket is in. Immutable. For more on states see\n"
      "mudsock.Mudsock.push_ih");
    PySocket_addGetSetter("idle_time", PySocket_getidletime, NULL,
      "How long (in seconds) the socket's input handler has been idle for. Immutable.");
    PySocket_addGetSetter("hostname", PySocket_gethostname, NULL,
      "The dns address that the socket is connected from. Immutable.");

    PySocket_addGetSetter("cols", PySocket_getcols, PySocket_setcols,
      "The width of the client's output in columns.");
    PySocket_addGetSetter("rows", PySocket_getrows, PySocket_setrows,
      "The height of the client's output in rows.");

    // add all of the basic methods
    PySocket_addMethod("getAuxiliary", PySocket_get_auxiliary, METH_VARARGS,
      "getAuxiliary(name)\n\n"
      "Returns socket's auxiliary data of the specified name.");
    PySocket_addMethod("aux", PySocket_get_auxiliary, METH_VARARGS,
      "Alias for mudsock.Mudsock.getAuxiliary");
    PySocket_addMethod("send", PySocket_send, METH_KEYWORDS,
      "send(mssg, dict = None, newline = True)\n"
      "\n"
      "Sends message to the socket. Messages can have scripts embedded in\n" 
      "them, using [ and ]. If so, a variable dictionary must be provided. By\n"
      "default, 'me' references the socket being sent the message.");
    PySocket_addMethod("trans_raw", PySocket_send_rraw, METH_VARARGS,
      "trans_raw(mssg)\n\n"
      "Sends text to the socket. No appended newline, and no checking for the prompt.");
    PySocket_addMethod("send_raw", PySocket_send_raw, METH_VARARGS,
      "send_raw(mssg)\n\n"
      "Sends text to the socket. No appended newline.");
    PySocket_addMethod("pop_ih", PySocket_pop_ih, METH_NOARGS,
      "pop_ih()\n\n"
      "Pops the socket's current input handler from its input handler stack.");
    PySocket_addMethod("push_ih", PySocket_push_ih, METH_VARARGS,
      "push_ih(handler_func, prompt_func, state=None)\n\n"
      "Pushes a new input handler and prompt pair onto the socket's input\n"
      "handler stack. Optionally, a (String) state value can be supplied.\n"
      "Input handlers take two arguments: the socket and a string command.\n"
      "Prompts take one argument: the socket. They should send the relevant\n"
      "text for the prompt to the socket.");
    PySocket_addMethod("replace_ih", PySocket_replace_ih, METH_VARARGS,
      "repalce_ih(handler_func, prompt_func, state=None)\n\n"
      "Calls pop_ih, followed by push_ih.");
    PySocket_addMethod("close", PySocket_close, METH_VARARGS,
      "close()\n\n"
      "Closes the socket's connection.");
    PySocket_addMethod("bust_prompt", PySocket_bust_prompt, METH_NOARGS,
      "bust_prompt()\n\n"
      "Busts the socket's prompt so it will be displayed next pulse.");
    PySocket_addMethod("edit_text", PySocket_edit_text, METH_VARARGS, 
      "edit_text(dflt_value, on_complete, mode='text')\n\n"
      "Enter the text editor, and set its default value. When the text editor\n"
      "is edited, call on_complete. This function should take two arguments:\n"
      "the socket doing the editing, and the output of the editor. Mode can\n"
      "be 'text' or 'script'.");

    // add in all the getsetters and methods
    makePyType(&PySocket_Type, pysocket_getsetters, pysocket_methods);
    deleteListWith(pysocket_getsetters, free); pysocket_getsetters = NULL;
    deleteListWith(pysocket_methods,    free); pysocket_methods    = NULL;

    // make sure the socket class is ready to be made
    if (PyType_Ready(&PySocket_Type) < 0)
        return;

    // initialize the module
    module = Py_InitModule3("mudsock", socket_module_methods,
      "Contains the Python wrapper for sockets, and utilities for listing\n"
      "currently connected sockets.");

    // make sure the module parsed OK
    if (module == NULL)
      return;

    // add the Socket class to the socket module
    PyTypeObject *type = &PySocket_Type;
    PyModule_AddObject(module, "Mudsock", (PyObject *)type);
    Py_INCREF(&PySocket_Type);
}

int PySocket_Check(PyObject *value) {
  return PyObject_TypeCheck(value, &PySocket_Type);
}

int PySocket_AsUid(PyObject *sock) {
  return ((PySocket *)sock)->uid;
}

SOCKET_DATA *PySocket_AsSocket(PyObject *ch) {
  return propertyTableGet(sock_table, PySocket_AsUid(ch));
}

PyObject *
newPySocket(SOCKET_DATA *sock) {
  PySocket *pysock = (PySocket *)PySocket_new(&PySocket_Type, NULL, NULL);
  pysock->uid = socketGetUID(sock);
  return (PyObject *)pysock;
}