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