nakedmudv3.3/
nakedmudv3.3/lib/
nakedmudv3.3/lib/logs/
nakedmudv3.3/lib/misc/
nakedmudv3.3/lib/players/
nakedmudv3.3/lib/txt/
nakedmudv3.3/lib/world/
nakedmudv3.3/lib/world/examples/
nakedmudv3.3/lib/world/examples/mproto/
nakedmudv3.3/lib/world/examples/oproto/
nakedmudv3.3/lib/world/examples/reset/
nakedmudv3.3/lib/world/examples/rproto/
nakedmudv3.3/lib/world/examples/trigger/
nakedmudv3.3/lib/world/limbo/
nakedmudv3.3/lib/world/limbo/room/
nakedmudv3.3/lib/world/limbo/rproto/
nakedmudv3.3/src/alias/
nakedmudv3.3/src/char_vars/
nakedmudv3.3/src/editor/
nakedmudv3.3/src/example_module/
nakedmudv3.3/src/help/
nakedmudv3.3/src/set_val/
nakedmudv3.3/src/socials/
nakedmudv3.3/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"



//*****************************************************************************
// 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_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_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;

  if(sock == NULL)
    return NULL;

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

  socketPushPyInputHandler(sock, handler, prompt);
  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_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;
  }
}

PyObject *PySocket_send(PySocket *self, PyObject *value) {
  PyObject *retval = PySocket_send_raw(self, value);
  if(retval == NULL)
    return NULL;
  SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self);
  send_to_socket(sock, "\r\n");
  Py_DECREF(retval);
  return Py_BuildValue("i", 1);
}

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);
}



//*****************************************************************************
// 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,
    "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.");
    PySocket_addGetSetter("account", PySocket_getaccount, NULL,
			   "the socket's account.");
    PySocket_addGetSetter("character", PySocket_getchar, NULL,
			   "the socket's character.");
    PySocket_addGetSetter("char", PySocket_getchar, NULL,
			   "the socket's character.");
    PySocket_addGetSetter("ch",   PySocket_getchar, NULL,
			   "the socket's character.");
    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,
			  "Returns whether or not the socket is ready for use. "
			  "Sockets become available after their dns resolves.");

    // add all of the basic methods
    PySocket_addMethod("getAuxiliary", PySocket_get_auxiliary, METH_VARARGS,
		       "gets the socket auxiliary data with given key.");
    PySocket_addMethod("send", PySocket_send, METH_VARARGS,
		       "sends text to the socket with appended newline.");
    PySocket_addMethod("send_raw", PySocket_send_raw, METH_VARARGS,
		       "sends text to the socket.");
    PySocket_addMethod("pop_ih", PySocket_pop_ih, METH_NOARGS,
			"Pops the socket's current input handler.");
    PySocket_addMethod("push_ih", PySocket_push_ih, METH_VARARGS,
			"pushes on a new input handler.");
    PySocket_addMethod("replace_ih", PySocket_replace_ih, METH_VARARGS,
		       "replaces the socket's input handler.");
    PySocket_addMethod("close", PySocket_close, METH_VARARGS,
		       "closes the socket.");
    PySocket_addMethod("bust_prompt", PySocket_bust_prompt, METH_NOARGS,
		       "busts the socket's prompt so it will be displayed.");

    // 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,
			    "The socket module, for all MUD socket-related "
			    "stuff.");

    // 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;
}