X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=innd%2Fpython.c;fp=innd%2Fpython.c;h=0000000000000000000000000000000000000000;hb=b7a32e2d73e3ab1add8208d3e157f7269a31ef4d;hp=f14a312cec47fd6b3f29a450a65a7f3f06074c0a;hpb=ac902a8299ff4469b356836f431ead31c3377377;p=innduct.git diff --git a/innd/python.c b/innd/python.c deleted file mode 100644 index f14a312..0000000 --- a/innd/python.c +++ /dev/null @@ -1,732 +0,0 @@ -/* $Id: python.c 7891 2008-06-22 09:59:11Z iulius $ -** -** python.c: Embed Python in the style of innd's TCL and Perl stuff. -** -** Written by G.J. Andruk patterned after -** TCL/Perl work by Bob Heiney and Christophe Wolfhugel and a whole -** bunch of other people mentioned in the docs and sources for the -** other filters. -** -** The astute reader may notice the commission of blatant atrocities -** against Python's OO model here. Don't tell Guido. -** -** A quick note regarding Python exceptions: functions like -** PyObject_GetAttrString(PyObject *o, const char *attr_name) -** raise an exception when they fail, even though they return NULL. -** And as exceptions accumulate from caller to caller and so on, -** it generates weird issues with Python scripts afterwards. So such -** uses should be checked before. For instance with: -** PyObject_HasAttrString(PyObject *o, const char *attr_name). -*/ - -#include "config.h" -#include "clibrary.h" - -#include "inn/innconf.h" -#include "innd.h" - - -#if defined(DO_PYTHON) - -#include "Python.h" - - -bool PythonFilterActive; -char *filterPath; /* this gets set in art.c */ -PyObject *PYFilterObject = NULL; -PyObject *PYFilterModule = NULL; - -/* article filter bits and pieces */ -PyObject *PYheaders = NULL; -PyObject **PYheaditem; -PyObject **PYheadkey; -PyObject *PYpathkey, *PYlineskey, *PYbodykey; - -/* external functions */ -PyObject *msgid_method = NULL; -PyObject *art_method = NULL; -PyObject *mode_method = NULL; -PyObject *pre_reload_method = NULL; -PyObject *close_method = NULL; - - - -/* -** Turn filtering on or off. -*/ -void -PYfilter(value) - bool value; -{ - PythonFilterActive = value; - syslog(L_NOTICE, "%s Python filtering %s", LogName, - PythonFilterActive ? "enabled" : "disabled"); -} - - - -/* -** Front end for PYfilter() -*/ -const char * -PYcontrol(char **av) -{ - char *p; - extern bool PythonFilterActive; - - switch (av[0][0]) { - default: - return "1 Bad flag"; - case 'y': - if (PythonFilterActive) - return "1 Python filter already enabled"; - else if (PYFilterObject == NULL) - return "1 Python filter not defined" ; - PYfilter(true); - break; - case 'n': - if (!PythonFilterActive) - return "1 Python filter already disabled"; - PYfilter(false); - break; - } - return NULL; -} - - - - -/* -** Reject articles we don't like. -*/ -char * -PYartfilter(const ARTDATA *data, char *artBody, long artLen, int lines) -{ - const ARTHEADER *hp; - const HDRCONTENT *hc = data->HdrContent; - int hdrnum; - int i; - char *p, save; - static char buf[256]; - PyObject *result; - - if (!PythonFilterActive || PYFilterObject == NULL || art_method == NULL) - return NULL; - - /* Add headers to the dictionary... */ - hdrnum = 0; - for (i = 0 ; i < MAX_ARTHEADER ; i++) { - if (HDR_FOUND(i)) { - hp = &ARTheaders[i]; - PYheaditem[hdrnum] = PyBuffer_FromMemory(HDR(i), HDR_LEN(i)); - } else - PYheaditem[hdrnum] = Py_None; - PyDict_SetItem(PYheaders, PYheadkey[hdrnum], PYheaditem[hdrnum]); - hdrnum++; - } - - /* ...then the body... */ - if (artLen && artBody != NULL) - PYheaditem[hdrnum] = PyBuffer_FromMemory(artBody, --artLen); - else - PYheaditem[hdrnum] = Py_None; - PyDict_SetItem(PYheaders, PYbodykey, PYheaditem[hdrnum++]); - - /* ...and finally, the line count. */ - PYheaditem[hdrnum] = PyInt_FromLong((long) lines); - PyDict_SetItem(PYheaders, PYlineskey, PYheaditem[hdrnum++]); - - /* Now see if the filter likes it. */ - result = PyObject_CallFunction(art_method, "O", PYheaders); - if ((result != NULL) && PyObject_IsTrue(result)) - strlcpy(buf, PyString_AS_STRING(result), sizeof(buf)); - else - *buf = '\0'; - Py_XDECREF(result); - - /* Clean up after ourselves */ - PyDict_Clear(PYheaders); - for (i = 0; i < hdrnum; i++) - if (PYheaditem[i] != Py_None) - Py_DECREF(PYheaditem[i]); - - if (*buf != '\0') - return buf; - return NULL; -} - - - -/* -** Refuse message IDs offered thru CHECK or IHAVE that we don't like. -*/ -char * -PYmidfilter(messageID, msglen) - char *messageID; - int msglen; -{ - static char buf[256]; - PyObject *result; - - if (!PythonFilterActive || PYFilterObject == NULL || msgid_method == NULL) - return NULL; - - result = PyObject_CallFunction(msgid_method, "s#", messageID, msglen); - if ((result != NULL) && PyObject_IsTrue(result)) - strlcpy(buf, PyString_AS_STRING(result), sizeof(buf)); - else - *buf = '\0'; - Py_XDECREF(result); - - if (*buf != '\0') - return buf; - return NULL; -} - - - -/* -** Tell the external module about innd's state. -*/ -void -PYmode(Mode, NewMode, reason) - OPERATINGMODE Mode, NewMode; - char *reason; -{ - PyObject *result; - char oldmode[10], newmode[10]; - - if (!PythonFilterActive || PYFilterObject == NULL || mode_method == NULL) - return; - - switch (Mode) { - default: strlcpy(oldmode, "unknown", 10); break; - case OMrunning: strlcpy(oldmode, "running", 10); break; - case OMpaused: strlcpy(oldmode, "paused", 10); break; - case OMthrottled: strlcpy(oldmode, "throttled", 10); break; - } - - switch (NewMode) { - default: strlcpy(newmode, "unknown", 10); break; - case OMrunning: strlcpy(newmode, "running", 10); break; - case OMpaused: strlcpy(newmode, "paused", 10); break; - case OMthrottled: strlcpy(newmode, "throttled", 10); break; - } - - result = PyObject_CallFunction(mode_method, "sss", - oldmode, newmode, reason); - Py_XDECREF(result); -} - - - -/* -** Called by the external module so it can register itself with innd. -*/ -static PyObject * -PY_set_filter_hook(dummy, args) - PyObject *dummy, *args; -{ - PyObject *result = NULL; - PyObject *temp; - - if (PyArg_ParseTuple(args, "O:set_filter_hook", &temp)) { - Py_XINCREF(temp); - Py_XDECREF(PYFilterObject); - PYFilterObject = temp; - Py_INCREF(Py_None); - result = Py_None; - } - return result; -} - - - -/* -** Allow external module to ask innd if an ID is in history. -*/ -static PyObject * -PY_havehist(self, args) - PyObject *self, *args; -{ - char *msgid; - int msgidlen; - - if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen)) - return NULL; - - if (HIScheck(History, msgid)) - return PyInt_FromLong(1); - return PyInt_FromLong(0); -} - - - -/* -** Allow external module to locally delete an article. -*/ -static PyObject * -PY_cancel(self, args) - PyObject *self, *args; -{ - char *msgid; - int msgidlen; - char *parambuf[2]; - - if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen)) - return NULL; - - parambuf[0]= msgid; - parambuf[1]= 0; - - if (!CCcancel(parambuf)) - return PyInt_FromLong(1); - return PyInt_FromLong(0); -} - - - -/* -** Stuff an ID into history so that it will be refused later. -*/ -static PyObject * -PY_addhist(self, args) - PyObject *self, *args; -{ - char *msgid; - int msgidlen; - char *articlepaths = ""; - char tbuff[12]; - char *parambuf[6]; - - if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen)) - return NULL; - - snprintf(tbuff, sizeof(tbuff), "%d", time(NULL)); - - parambuf[0] = msgid; - parambuf[1] = parambuf[2] = parambuf[3] = tbuff; - parambuf[4] = articlepaths; - parambuf[5] = 0; - - if (!CCaddhist(parambuf)) - return PyInt_FromLong(1); - return PyInt_FromLong(0); -} - - - -/* -** Get a newsgroup's status flag (j, m, n, x, y, =other.group) -*/ -static PyObject * -PY_newsgroup(self, args) - PyObject *self, *args; -{ - char *newsgroup; - int nglen; - NEWSGROUP *ngp; - char *end; - char *rest; - int size; - - if (!PyArg_ParseTuple(args, "s#", &newsgroup, &nglen)) - return NULL; - - ngp = NGfind(newsgroup); - if (ngp == NULL) - return PyString_FromStringAndSize(NULL, 0); - - /* ngp->Rest is newline-terminated; find the end. */ - end = strchr(ngp->Rest, '\n'); - if (end == NULL) - size = strlen(ngp->Rest); - else - size = end - ngp->Rest; - - /* If an alias is longer than this, active is probably broken. */ - if (size > MAXHEADERSIZE) { - syslog(L_ERROR, "too-long flag field in active for %s", newsgroup); - size = MAXHEADERSIZE; - } - - return PyString_FromStringAndSize(ngp->Rest, size); -} - - - -/* -** Return an article header to the external module as a string. We -** don't use a buffer object here because that would make it harder, -** for example, to compare two on-spool articles. -*/ -static PyObject * -PY_head(self, args) - PyObject *self, *args; -{ - char *msgid; - int msgidlen; - char *p; - TOKEN token; - ARTHANDLE *art; - PyObject *header; - int headerlen; - - if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen)) - return NULL; - - if (! HISlookup(History, msgid, NULL, NULL, NULL, &token)) - return Py_BuildValue("s", ""); - if ((art = SMretrieve(token, RETR_HEAD)) == NULL) - return Py_BuildValue("s", ""); - p = FromWireFmt(art->data, art->len, &headerlen); - SMfreearticle(art); - header = PyString_FromStringAndSize(p, headerlen); - free(p); - - return header; -} - - - -/* -** Return a whole article to the external module as a string. -*/ -static PyObject * -PY_article(self, args) - PyObject *self, *args; -{ - char *msgid; - int msgidlen; - char *p; - TOKEN token; - ARTHANDLE *arth; - PyObject *art; - int artlen; - - if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen)) - return NULL; - - if (! HISlookup(History, msgid, NULL, NULL, NULL, &token)) - return Py_BuildValue("s", ""); - if ((arth = SMretrieve(token, RETR_ALL)) == NULL) - return Py_BuildValue("s", ""); - p = FromWireFmt(arth->data, arth->len, &artlen); - SMfreearticle(arth); - art = PyString_FromStringAndSize(p, artlen); - free(p); - - return art; -} - - - -/* -** Python's syslog module isn't compiled in by default. It's easier -** to do it this way, and the switch block looks pretty in a color -** editor). -*/ -static PyObject * -PY_syslog(self, args) - PyObject *self, *args; -{ - char *loglevel; - int levellen; - char *logmsg; - int msglen; - int priority; - - if (!PyArg_ParseTuple(args, "s#s#", - &loglevel, &levellen, &logmsg, &msglen)) - return NULL; - - switch (*loglevel) { - default: priority = LOG_NOTICE ; - case 'd': case 'D': priority = LOG_DEBUG ; break; - case 'i': case 'I': priority = LOG_INFO ; break; - case 'n': case 'N': priority = LOG_NOTICE ; break; - case 'w': case 'W': priority = LOG_WARNING ; break; - case 'e': case 'E': priority = LOG_ERR ; break; - case 'c': case 'C': priority = LOG_CRIT ; break; - case 'a': case 'A': priority = LOG_ALERT ; break; - } - - syslog(priority, "python: %s", logmsg); - - Py_INCREF(Py_None); - return Py_None; -} - - - -/* -** Compute a hash digest for a string. -*/ -static PyObject * -PY_hashstring(self, args) - PyObject *self, *args; -{ - char *instring, *wpos, *p, *q; - char *workstring = NULL; - int insize, worksize, newsize, i, wasspace; - int lines = 0; - HASH myhash; - - if (!PyArg_ParseTuple(args, "s#|i", &instring, &insize, &lines)) - return NULL; - - /* If a linecount is provided, munge before hashing. */ - if (lines > 0) { - worksize = insize; - - /* chop leading whitespace */ - for (p=instring ; worksize>0 && isspace(*p) ; p++) { - if (*p == '\n') - lines--; - worksize--; - } - wpos = p; - - /* and trailing */ - for (p=&wpos[worksize] ; worksize>0 && isspace(*p) ; p--) { - if (*p == '\n') - lines--; - worksize--; - } - - /* chop last 3 lines if we have >= 5. From above chop the - * last line has no CR so we use 1 less here. */ - if (lines >= 4) { - for (i=0, p=wpos+worksize ; i<2 ; p--) - if (*p == '\n') - i++; - worksize = p - wpos; - } - - /* Compress out multiple whitespace in the trimmed string. We - * do a copy because this is probably an original art - * buffer. */ - workstring = memcpy(xmalloc(worksize), wpos, worksize); - newsize = wasspace = 0; - p = wpos; - q = workstring; - for (i=0 ; ipathfilter, 1); - Py_Initialize(); - - /* It makes Python sad when its stdout and stderr are closed. */ - if ((fileno(stdout) == -1) || (fileno(stderr) == -1)) - PyRun_SimpleString - ("import sys; sys.stdout=sys.stderr=open('/dev/null', 'a')"); - - if (!Py_IsInitialized ()) { - syslog(L_ERROR, "python interpreter NOT initialized"); - return; - } - syslog(L_NOTICE, "python interpreter initialized OK"); - - Py_InitModule("INN", INNPyMethods); - - PYFilterModule = PyImport_ImportModule(_PATH_PYTHON_STARTUP_M); - if (PYFilterModule == NULL) - syslog(L_ERROR, "failed to import external python module"); - - if (PYFilterObject == NULL) { - syslog(L_ERROR, "python filter object is not defined"); - PYfilter(false); - } else { - PYfilter(true); - PYdefmethods(); - syslog(L_NOTICE, "defined python methods"); - } - - /* Grab space for these so we aren't forever recreating them. We also - put the body and the line count into PYheaditem, so it needs to be - two elements longer than the total number of headers. */ - PYheaders = PyDict_New(); - hdrcount = ARRAY_END(ARTheaders) - ARTheaders; - PYheaditem = xmalloc((hdrcount + 2) * sizeof(PyObject *)); - PYheadkey = xmalloc(hdrcount * sizeof(PyObject *)); - - /* Preallocate keys for the article dictionary */ - for (hp = ARTheaders; hp < ARRAY_END(ARTheaders); hp++) - PYheadkey[hp - ARTheaders] = PyString_InternFromString(hp->Name); - PYpathkey = PyString_InternFromString("Path"); - PYlineskey = PyString_InternFromString("__LINES__"); - PYbodykey = PyString_InternFromString("__BODY__"); -} - -#endif /* defined(DO_PYTHON) */