1/*
2 * Copyright 2001-2004 Brandon Long
3 * All Rights Reserved.
4 *
5 * ClearSilver Templating System
6 *
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
9 *
10 */
11
12#include <Python.h>
13#include "ClearSilver.h"
14
15#define NEO_CGI_MODULE
16#include "p_neo_util.h"
17
18static PyObject *CGIFinishedException;
19
20#define CGIObjectCheck(a) (!(strcmp((a)->ob_type->tp_name, CGIObjectType.tp_name)))
21
22typedef struct _CGIObject
23{
24   PyObject_HEAD
25   CGI *cgi;
26   PyObject *hdf;
27   PyObject *upload_cb;
28   PyObject *upload_rock;
29   int upload_error;
30} CGIObject;
31
32static PyObject *p_cgi_value_get_attr (CGIObject *self, char *name);
33static void p_cgi_dealloc (CGIObject *ho);
34
35PyTypeObject CGIObjectType = {
36  PyObject_HEAD_INIT(NULL)
37    0,			             /*ob_size*/
38  "CGIObjectType",	             /*tp_name*/
39  sizeof(CGIObject),	     /*tp_size*/
40  0,			             /*tp_itemsize*/
41  /* methods */
42  (destructor)p_cgi_dealloc,	     /*tp_dealloc*/
43  0,			             /*tp_print*/
44  (getattrfunc)p_cgi_value_get_attr,     /*tp_getattr*/
45  0,			             /*tp_setattr*/
46  0,			             /*tp_compare*/
47  (reprfunc)0,                       /*tp_repr*/
48  0,                                 /* tp_as_number */
49  0,                                 /* tp_as_sequence */
50  0,                                 /* tp_as_mapping */
51  0,                                 /* tp_as_hash */
52};
53
54static void p_cgi_dealloc (CGIObject *ho)
55{
56  if (ho->cgi)
57  {
58    cgi_destroy (&(ho->cgi));
59  }
60  PyObject_DEL(ho);
61}
62
63PyObject * p_cgi_to_object (CGI *data)
64{
65  PyObject *rv;
66
67  if (data == NULL)
68  {
69    rv = Py_None;
70    Py_INCREF (rv);
71  }
72  else
73  {
74    CGIObject *ho = PyObject_NEW (CGIObject, &CGIObjectType);
75    if (ho == NULL) return NULL;
76    ho->cgi = data;
77    ho->hdf = p_hdf_to_object (data->hdf, 0);
78    Py_INCREF(ho->hdf);
79    rv = (PyObject *) ho;
80  }
81  return rv;
82}
83
84static PyObject * p_cgi_init (PyObject *self, PyObject *args)
85{
86  CGI *cgi = NULL;
87  NEOERR *err;
88
89  err = cgi_init (&cgi, NULL);
90  if (err) return p_neo_error (err);
91  return p_cgi_to_object (cgi);
92}
93
94static PyObject * p_cgi_parse (PyObject *self, PyObject *args)
95{
96  CGI *cgi = ((CGIObject *) self)->cgi;
97  CGIObject *p_cgi = (CGIObject *) self;
98  PyObject *rv;
99  NEOERR *err;
100
101  p_cgi->upload_error = 0;
102
103  err = cgi_parse (cgi);
104  if (err) return p_neo_error (err);
105
106  if (p_cgi->upload_error)
107  {
108    p_cgi->upload_error = 0;
109    return NULL;
110  }
111
112  rv = Py_None;
113  Py_INCREF(rv);
114  return rv;
115}
116
117static int python_upload_cb (CGI *cgi, int nread, int expected)
118{
119  CGIObject *self = (CGIObject *)(cgi->data);
120  PyObject *cb, *rock;
121  PyObject *args, *result;
122  int r;
123
124  /* fprintf(stderr, "upload_cb: %d/%d\n", nread, expected); */
125  cb = self->upload_cb;
126  rock = self->upload_rock;
127
128  if (cb == NULL) return 0;
129  args = Py_BuildValue("(Oii)", rock, nread, expected);
130
131  if (args == NULL) {
132    self->upload_error = 1;
133    return 1;
134  }
135  result = PyEval_CallObject(cb, args);
136  Py_DECREF(args);
137  if (result != NULL && !PyInt_Check(result)) {
138    Py_DECREF(result);
139    result = NULL;
140    PyErr_SetString(PyExc_TypeError,
141	"upload_cb () returned non-integer");
142    self->upload_error = 1;
143    return 1;
144  }
145  r = PyInt_AsLong(result);
146  Py_DECREF(result);
147  result = NULL;
148  return r;
149}
150
151static PyObject * p_cgi_set_upload_cb (PyObject *self, PyObject *args)
152{
153  CGI *cgi = ((CGIObject *) self)->cgi;
154  CGIObject *p_cgi = (CGIObject *) self;
155  PyObject *rock, *cb;
156
157  if (!PyArg_ParseTuple(args, "OO:setUploadCB(rock, func)", &rock, &cb))
158    return NULL;
159
160  cgi->data = self;
161  cgi->upload_cb = python_upload_cb;
162  p_cgi->upload_cb = cb;
163  p_cgi->upload_rock = rock;
164  p_cgi->upload_error = 0;
165  Py_INCREF(cb);
166  Py_INCREF(rock);
167
168  Py_INCREF(Py_None);
169  return Py_None;
170}
171
172static PyObject * p_cgi_error (PyObject *self, PyObject *args)
173{
174  CGI *cgi = ((CGIObject *) self)->cgi;
175  char *s;
176  PyObject *rv;
177
178  if (!PyArg_ParseTuple(args, "s:error(str)", &s))
179    return NULL;
180
181  cgi_error (cgi, s);
182  rv = Py_None;
183  Py_INCREF(rv);
184  return rv;
185}
186
187static PyObject * p_cgi_display (PyObject *self, PyObject *args)
188{
189  CGI *cgi = ((CGIObject *) self)->cgi;
190  char *file;
191  PyObject *rv;
192  NEOERR *err;
193
194  if (!PyArg_ParseTuple(args, "s:display(file)", &file))
195    return NULL;
196
197  err = cgi_display (cgi, file);
198  if (err) return p_neo_error (err);
199  rv = Py_None;
200  Py_INCREF(rv);
201  return rv;
202}
203
204static PyObject * p_cgi_redirect (PyObject *self, PyObject *args)
205{
206  CGI *cgi = ((CGIObject *) self)->cgi;
207  char *s;
208  PyObject *rv;
209
210  if (!PyArg_ParseTuple(args, "s:redirect(str)", &s))
211    return NULL;
212
213  cgi_redirect (cgi, "%s", s);
214  rv = Py_None;
215  Py_INCREF(rv);
216  return rv;
217}
218
219static PyObject * p_cgi_redirect_uri (PyObject *self, PyObject *args)
220{
221  CGI *cgi = ((CGIObject *) self)->cgi;
222  char *s;
223  PyObject *rv;
224
225  if (!PyArg_ParseTuple(args, "s:redirectUri(str)", &s))
226    return NULL;
227
228  cgi_redirect_uri (cgi, "%s", s);
229  rv = Py_None;
230  Py_INCREF(rv);
231  return rv;
232}
233
234static PyObject * p_cgi_cookie_authority (PyObject *self, PyObject *args)
235{
236  CGI *cgi = ((CGIObject *) self)->cgi;
237  char *s, *host;
238  PyObject *rv;
239
240  if (!PyArg_ParseTuple(args, "s:cookieAuthority(host)", &host))
241    return NULL;
242
243  s = cgi_cookie_authority (cgi, host);
244  if (s == NULL)
245  {
246    rv = Py_None;
247    Py_INCREF(rv);
248  }
249  else
250  {
251    rv = Py_BuildValue ("s", s);
252  }
253  return rv;
254}
255
256static PyObject * p_cgi_cookie_set (PyObject *self, PyObject *args,
257    PyObject *keywds)
258{
259  CGI *cgi = ((CGIObject *) self)->cgi;
260  char *name, *value, *path = NULL, *domain = NULL, *time_str = NULL;
261  int persist = 0;
262  int secure = 0;
263  NEOERR *err;
264  static char *kwlist[] = {"name", "value", "path", "domain", "time_str", "persist", "secure", NULL};
265
266  if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|sssii:cookieSet()", kwlist, &name, &value, &path, &domain, &time_str, &persist, &secure))
267    return NULL;
268
269  err = cgi_cookie_set (cgi, name, value, path, domain, time_str, persist, secure);
270  if (err) return p_neo_error (err);
271  Py_INCREF(Py_None);
272  return Py_None;
273}
274
275static PyObject * p_cgi_cookie_clear (PyObject *self, PyObject *args)
276{
277  CGI *cgi = ((CGIObject *) self)->cgi;
278  char *name, *domain = NULL, *path = NULL;
279  NEOERR *err;
280
281  if (!PyArg_ParseTuple(args, "s|ss:cookieClear(name, domain, path)", &name, &domain, &path))
282    return NULL;
283
284  err = cgi_cookie_clear (cgi, name, domain, path);
285  if (err) return p_neo_error (err);
286  Py_INCREF(Py_None);
287  return Py_None;
288}
289
290static PyObject * p_cgi_filehandle (PyObject *self, PyObject *args)
291{
292  CGI *cgi = ((CGIObject *) self)->cgi;
293  char *name;
294  FILE *fp;
295
296  if (!PyArg_ParseTuple(args, "s:filehandle(form_name)", &name))
297    return NULL;
298
299  fp = cgi_filehandle (cgi, name);
300  if (fp == NULL)
301  {
302    Py_INCREF(Py_None);
303    return Py_None;
304  }
305  return PyFile_FromFile (fp, name, "w+", NULL);
306}
307
308static PyObject * p_cgi_cs_init (PyObject *self, PyObject *args)
309{
310  CGI *cgi = ((CGIObject *) self)->cgi;
311  NEOERR *err;
312  CSPARSE *cs;
313
314  if (!PyArg_ParseTuple(args, ":cs()"))
315    return NULL;
316
317  err = cgi_cs_init(cgi, &cs);
318  if (err) return p_neo_error (err);
319  return p_cs_to_object(cs);
320}
321
322static PyMethodDef CGIMethods[] =
323{
324#if 0
325  {"debugInit", p_cgi_debug_init, METH_VARARGS, NULL},
326  {"wrapInit", p_cgi_wrap_init, METH_VARARGS, NULL},
327#endif
328  {"parse", p_cgi_parse, METH_VARARGS, NULL},
329  {"setUploadCB", p_cgi_set_upload_cb, METH_VARARGS, NULL},
330  {"error", p_cgi_error, METH_VARARGS, NULL},
331  {"display", p_cgi_display, METH_VARARGS, NULL},
332  {"redirect", p_cgi_redirect, METH_VARARGS, NULL},
333  {"redirectUri", p_cgi_redirect_uri, METH_VARARGS, NULL},
334  {"cookieAuthority", p_cgi_cookie_authority, METH_VARARGS, NULL},
335  {"cookieSet", (PyCFunction)p_cgi_cookie_set, METH_VARARGS|METH_KEYWORDS, NULL},
336  {"cookieClear", p_cgi_cookie_clear, METH_VARARGS, NULL},
337  {"filehandle", p_cgi_filehandle, METH_VARARGS, NULL},
338  {"cs", p_cgi_cs_init, METH_VARARGS, NULL},
339  {NULL, NULL}
340};
341
342static PyObject * p_cgi_url_escape (PyObject *self, PyObject *args)
343{
344  char *s, *esc, *o = NULL;
345  NEOERR *err;
346  PyObject *rv;
347
348  if (!PyArg_ParseTuple(args, "s|s:urlEscape(str, other=None)", &s, &o))
349    return NULL;
350
351  err = cgi_url_escape_more (s, &esc, o);
352  if (err) return p_neo_error (err);
353  rv = Py_BuildValue ("s", esc);
354  free (esc);
355  return rv;
356}
357
358static PyObject * p_cgi_url_unescape (PyObject *self, PyObject *args)
359{
360  char *s;
361  PyObject *rv;
362  char *r;
363
364  if (!PyArg_ParseTuple(args, "s:urlUnescape(str)", &s))
365    return NULL;
366
367  r = strdup(s);
368  if (r == NULL) return PyErr_NoMemory();
369  cgi_url_unescape (r);
370  rv = Py_BuildValue ("s", r);
371  free (r);
372  return rv;
373}
374
375static PyObject * p_html_escape (PyObject *self, PyObject *args)
376{
377  char *s, *esc;
378  NEOERR *err;
379  PyObject *rv;
380  int len;
381
382  if (!PyArg_ParseTuple(args, "s#:htmlEscape(str)", &s, &len))
383    return NULL;
384
385  err = html_escape_alloc (s, len, &esc);
386  if (err) return p_neo_error (err);
387  rv = Py_BuildValue ("s", esc);
388  free (esc);
389  return rv;
390}
391
392static PyObject * p_html_strip (PyObject *self, PyObject *args)
393{
394  char *s, *esc;
395  NEOERR *err;
396  PyObject *rv;
397  int len;
398
399  if (!PyArg_ParseTuple(args, "s#:htmlStrip(str)", &s, &len))
400    return NULL;
401
402  err = html_strip_alloc (s, len, &esc);
403  if (err) return p_neo_error (err);
404  rv = Py_BuildValue ("s", esc);
405  free (esc);
406  return rv;
407}
408
409static PyObject * p_text_html (PyObject *self, PyObject *args, PyObject *keywds)
410{
411  char *s, *esc;
412  NEOERR *err;
413  PyObject *rv;
414  int len;
415  HTML_CONVERT_OPTS opts;
416  static char *kwlist[] = {"text", "bounce_url", "url_class", "url_target", "mailto_class", "long_lines", "space_convert", "newlines_convert", "longline_width", "check_ascii_art", "link_name", NULL};
417
418  /* These defaults all come from the old version */
419  opts.bounce_url = NULL;
420  opts.url_class = NULL;
421  opts.url_target = "_blank";
422  opts.mailto_class = NULL;
423  opts.long_lines = 0;
424  opts.space_convert = 0;
425  opts.newlines_convert = 1;
426  opts.longline_width = 75; /* This hasn't been used in a while, actually */
427  opts.check_ascii_art = 1;
428  opts.link_name = NULL;
429
430  if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#|ssssiiiiis:text2html(text)",
431	kwlist,
432	&s, &len, &(opts.bounce_url), &(opts.url_class), &(opts.url_target),
433	&(opts.mailto_class), &(opts.long_lines), &(opts.space_convert),
434	&(opts.newlines_convert), &(opts.longline_width), &(opts.check_ascii_art), &(opts.link_name)))
435    return NULL;
436
437  err = convert_text_html_alloc_options (s, len, &esc, &opts);
438  if (err) return p_neo_error (err);
439  rv = Py_BuildValue ("s", esc);
440  free (esc);
441  return rv;
442}
443
444PyObject *p_cgi_value_get_attr (CGIObject *ho, char *name)
445{
446  if (!strcmp(name, "hdf"))
447  {
448    Py_INCREF(ho->hdf);
449    return ho->hdf;
450  }
451  return Py_FindMethod(CGIMethods, (PyObject *)ho, name);
452}
453
454/* Enable wrapping of newlib stdin/stdout output to go through python */
455typedef struct wrapper_data
456{
457  PyObject *p_stdin;
458  PyObject *p_stdout;
459  PyObject *p_env;
460} WRAPPER_DATA;
461
462static WRAPPER_DATA Wrapper = {NULL, NULL, NULL};
463
464static char cgiwrap_doc[] = "cgiwrap(stdin, stdout, env)\nMethod that will cause all cgiwrapped stdin/stdout functions to be redirected to the python stdin/stdout file objects specified.  Also redirect getenv/putenv calls (env should be either a python dictionary or os.environ)";
465static PyObject * cgiwrap (PyObject *self, PyObject *args)
466{
467  PyObject *p_stdin;
468  PyObject *p_stdout;
469  PyObject *p_env;
470
471  if (!PyArg_ParseTuple(args, "OOO:cgiwrap(stdin, stdout, env)", &p_stdin, &p_stdout, &p_env))
472    return NULL;
473
474  if (p_stdin != Py_None)
475  {
476    if (Wrapper.p_stdin != NULL)
477    {
478      Py_DECREF (Wrapper.p_stdin);
479    }
480    Wrapper.p_stdin = p_stdin;
481    Py_INCREF (Wrapper.p_stdin);
482  }
483  if (p_stdout != Py_None)
484  {
485    if (Wrapper.p_stdout != NULL)
486    {
487      Py_DECREF (Wrapper.p_stdout);
488    }
489    Wrapper.p_stdout = p_stdout;
490    Py_INCREF (Wrapper.p_stdout);
491  }
492  if (p_env != Py_None)
493  {
494    if (Wrapper.p_env != NULL)
495    {
496      Py_DECREF (Wrapper.p_env);
497    }
498    Wrapper.p_env = p_env;
499    Py_INCREF (Wrapper.p_env);
500  }
501
502  Py_INCREF(Py_None);
503  return Py_None;
504}
505
506static int p_writef (void *data, const char *fmt, va_list ap)
507{
508  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
509  PyObject *str;
510  char *buf;
511  int len;
512  int err;
513
514
515  buf = vsprintf_alloc(fmt, ap);
516  len = visprintf_alloc(&buf, fmt, ap);
517
518  if (buf == NULL)
519    return 0;
520
521  str = PyString_FromStringAndSize (buf, len);
522  free(buf);
523
524  err = PyFile_WriteObject(str, wrap->p_stdout, Py_PRINT_RAW);
525  Py_DECREF(str);
526
527  if (err == 0)
528  {
529    PyErr_Clear();
530    return len;
531  }
532  PyErr_Clear();
533  return err;
534}
535
536static int p_write (void *data, const char *buf, int len)
537{
538  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
539  PyObject *s;
540  int err;
541
542  s = PyString_FromStringAndSize (buf, len);
543
544  err = PyFile_WriteObject(s, wrap->p_stdout, Py_PRINT_RAW);
545  Py_DECREF(s);
546
547  if (err == 0)
548  {
549    PyErr_Clear();
550    return len;
551  }
552  PyErr_Clear();
553  return err;
554}
555
556/* Similar to the PyFile_GetLine function, this one invokes read on the
557 * file object */
558static PyObject *PyFile_Read (PyObject *f, int n)
559{
560  if (f == NULL)
561  {
562    PyErr_BadInternalCall();
563    return NULL;
564  }
565  /* If this was in the python fileobject code, we could handle this
566   * directly for builtin file objects.  Oh well. */
567  /* if (!PyFile_Check(f))*/
568  else
569  {
570    PyObject *reader;
571    PyObject *args;
572    PyObject *result;
573    reader = PyObject_GetAttrString(f, "read");
574    if (reader == NULL)
575      return NULL;
576    if (n <= 0)
577      args = Py_BuildValue("()");
578    else
579      args = Py_BuildValue("(i)", n);
580    if (args == NULL) {
581      Py_DECREF(reader);
582      return NULL;
583    }
584    result = PyEval_CallObject(reader, args);
585    Py_DECREF(reader);
586    Py_DECREF(args);
587    if (result != NULL && !PyString_Check(result)) {
588      Py_DECREF(result);
589      result = NULL;
590      PyErr_SetString(PyExc_TypeError,
591	  "object.read() returned non-string");
592    }
593    return result;
594  }
595}
596
597static int p_read (void *data, char *ptr, int len)
598{
599  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
600  PyObject *buf;
601  char *s;
602
603  buf = PyFile_Read (wrap->p_stdin, len);
604
605  if (buf == NULL)
606  {
607    PyErr_Clear();
608    return -1;
609  }
610
611  len = PyString_Size(buf);
612  s = PyString_AsString(buf);
613
614  memcpy (ptr, s, len);
615
616  Py_DECREF(buf);
617
618  PyErr_Clear();
619  return len;
620}
621
622/* We can't really have an error return from this (and the other
623 * cgiwrap) function, because the API doesn't have an error return,
624 * and if we get back to python, the error will occur at the next random
625 * place that python actually checks for errors independent of an error
626 * return.  Not the best way to do things, but its what we've got.  Some
627 * of these we can check for in cgiWrap() */
628static char *p_getenv (void *data, const char *s)
629{
630  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
631  PyObject *get;
632  PyObject *args = NULL;
633  PyObject *result;
634  char *ret = NULL;
635
636  get = PyObject_GetAttrString(wrap->p_env, "__getitem__");
637  if (get != NULL)
638  {
639    args = Py_BuildValue("(s)", s);
640    if (args == NULL) {
641      Py_DECREF(get);
642      PyErr_Clear();
643      return NULL;
644    }
645  }
646  else
647  {
648    /* Python 1.5.2 and earlier don't have __getitem__ on the standard
649     * dict object, so we'll just use get for them */
650
651    get = PyObject_GetAttrString(wrap->p_env, "get");
652    if (get != NULL)
653    {
654      args = Py_BuildValue("(s,O)", s, Py_None);
655      if (args == NULL)
656      {
657	Py_DECREF(get);
658	PyErr_Clear();
659	return NULL;
660      }
661    }
662  }
663  if (get == NULL)
664  {
665    ne_warn("Unable to get __getitem__ from env");
666    PyErr_Clear();
667    return NULL;
668  }
669  result = PyEval_CallObject(get, args);
670  Py_DECREF(get);
671  Py_DECREF(args);
672  if (result != NULL && !PyString_Check(result) && (result != Py_None))
673  {
674    Py_DECREF(result);
675    result = NULL;
676    PyErr_SetString(PyExc_TypeError,
677	"env.get() returned non-string");
678  }
679  if (result != NULL && result != Py_None)
680  {
681    ret = strdup (PyString_AsString(result));
682    Py_DECREF (result);
683  }
684
685  PyErr_Clear();
686  return ret;
687}
688
689static int p_iterenv (void *data, int x, char **rk, char **rv)
690{
691  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
692  PyObject *items;
693  PyObject *env_list;
694  PyObject *result;
695  PyObject *k, *v;
696
697  items = PyObject_GetAttrString(wrap->p_env, "items");
698  if (items == NULL)
699  {
700    ne_warn ("p_iterenv: Unable to get items method");
701    PyErr_Clear();
702    return -1;
703  }
704  env_list = PyEval_CallObject(items, NULL);
705  Py_DECREF(items);
706  if (env_list == NULL)
707  {
708    ne_warn ("p_iterenv: Unable to call items method");
709    PyErr_Clear();
710    return -1;
711  }
712  if (x >= PyList_Size(env_list))
713  {
714    *rk = NULL;
715    *rv = NULL;
716    Py_DECREF(env_list);
717    return 0;
718  }
719  result = PyList_GetItem (env_list, x);
720  if (result == NULL)
721  {
722    ne_warn ("p_iterenv: Unable to get env %d", x);
723    Py_DECREF(env_list);
724    PyErr_Clear();
725    return -1;
726  }
727  k = PyTuple_GetItem (result, 0);
728  v = PyTuple_GetItem (result, 1);
729  if (k == NULL || v == NULL)
730  {
731    ne_warn ("p_iterenv: Unable to get k,v %p,%p", k, v);
732    Py_DECREF(env_list);
733    PyErr_Clear();
734    return -1;
735  }
736  *rk = strdup(PyString_AsString(k));
737  *rv = strdup(PyString_AsString(v));
738  if (*rk == NULL || *rv == NULL)
739  {
740    if (*rk) free (*rk);
741    if (*rv) free (*rv);
742    Py_DECREF(env_list);
743    PyErr_Clear();
744    return -1;
745  }
746
747  Py_DECREF(env_list);
748  PyErr_Clear();
749  return 0;
750}
751
752static int p_putenv (void *data, const char *k, const char *v)
753{
754  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
755  PyObject *set;
756  PyObject *args;
757  PyObject *result;
758
759  if (k == NULL || v == NULL) return -1;
760
761  set = PyObject_GetAttrString(wrap->p_env, "__setitem__");
762  if (set == NULL)
763  {
764    PyErr_Clear();
765    return -1;
766  }
767  args = Py_BuildValue("(s,s)", k, v);
768
769  if (args == NULL) {
770    Py_DECREF(set);
771    PyErr_Clear();
772    return -1;
773  }
774  result = PyEval_CallObject(set, args);
775  Py_DECREF(set);
776  Py_DECREF(args);
777  if (result == NULL)
778  {
779    PyErr_Clear();
780    return -1;
781  }
782  Py_DECREF(result);
783  PyErr_Clear();
784  return 0;
785}
786
787static void p_cgiwrap_init(PyObject *m)
788{
789  PyObject *sys, *os, *p_stdin, *p_stdout, *args, *p_env;
790#if 0
791  PyObject *argv;
792  int x;
793#endif
794
795  /* Set up the python wrapper
796   * This might not be enough to actually continue to point to
797   * sys.stdin/sys.stdout, we'd probably have to actually do the lookup
798   * every time... if we need that functionality
799   */
800  sys = PyImport_ImportModule("sys");
801  os = PyImport_ImportModule("os");
802  if (sys)
803  {
804    p_stdin = PyObject_GetAttrString(sys, "stdin");
805    p_stdout = PyObject_GetAttrString(sys, "stdout");
806#if 0
807    argv = PyObject_GetAttrString(sys, "argv");
808    if (argv)
809    {
810      Argc = PyList_Size (argv);
811      if (Argc != -1)
812      {
813
814	Argv = (char **) malloc (sizeof (char *) * (Argc+1));
815	for (x = 0; x < Argc; x++)
816	{
817	  PyObject *a;
818	  char *b;
819
820	  a = PyList_GetItem (argv, x);
821	  if (a == NULL)
822	    break;
823	  b = PyString_AsString(a);
824	  if (b == NULL)
825	    break;
826	  Argv[x] = b;
827	}
828	Argv[x] = NULL;
829      }
830    }
831#endif
832    if (os)
833    {
834      p_env = PyObject_GetAttrString(os, "environ");
835    }
836    else
837    {
838      Py_INCREF(Py_None);
839      p_env = Py_None;
840    }
841    args = Py_BuildValue("(O,O,O)", p_stdin, p_stdout, p_env);
842    if (args)
843    {
844      cgiwrap_init_emu (&Wrapper, p_read, p_writef, p_write, p_getenv, p_putenv, p_iterenv);
845      cgiwrap (m, args);
846      Py_DECREF(args);
847    }
848  }
849}
850
851static PyObject * p_ignore (PyObject *self, PyObject *args)
852{
853  int i = 0;
854
855  if (!PyArg_ParseTuple(args, "i:IgnoreEmptyFormVars(bool)", &i))
856    return NULL;
857
858  IgnoreEmptyFormVars = i;
859  Py_INCREF(Py_None);
860  return Py_None;
861}
862
863static PyObject * p_export_date (PyObject *self, PyObject *args)
864{
865  NEOERR *err;
866  PyObject *ho;
867  int i = 0;
868  char *prefix;
869  char *timezone;
870  HDF *hdf;
871
872  if (!PyArg_ParseTuple(args, "Ossi:exportDate(hdf, prefix, timezone, time_t)", &ho, &prefix, &timezone, &i))
873    return NULL;
874
875  hdf = p_object_to_hdf (ho);
876  if (hdf == NULL)
877  {
878    PyErr_SetString(PyExc_TypeError, "First argument must be an HDF Object");
879    return NULL;
880  }
881
882  err = export_date_time_t (hdf, prefix, timezone, i);
883  if (err) return p_neo_error (err);
884
885  Py_INCREF(Py_None);
886  return Py_None;
887}
888
889static PyObject * p_update (PyObject *self, PyObject *args)
890{
891  if (_PyImport_FindExtension("neo_util","neo_util") == NULL)
892    initneo_util();
893
894  if (_PyImport_FindExtension("neo_cs","neo_cs") == NULL)
895    initneo_cs();
896
897  Py_INCREF(Py_None);
898  return Py_None;
899}
900
901static PyMethodDef ModuleMethods[] =
902{
903  {"CGI", p_cgi_init, METH_VARARGS, NULL},
904  {"urlEscape", p_cgi_url_escape, METH_VARARGS, NULL},
905  {"urlUnescape", p_cgi_url_unescape, METH_VARARGS, NULL},
906  {"htmlEscape", p_html_escape, METH_VARARGS, NULL},
907  {"htmlStrip", p_html_strip, METH_VARARGS, NULL},
908  {"text2html", (PyCFunction)p_text_html, METH_VARARGS|METH_KEYWORDS, NULL},
909  {"cgiWrap", cgiwrap, METH_VARARGS, cgiwrap_doc},
910  {"IgnoreEmptyFormVars", p_ignore, METH_VARARGS, NULL},
911  {"exportDate", p_export_date, METH_VARARGS, NULL},
912  {"update", p_update, METH_VARARGS, NULL},
913  {NULL, NULL}
914};
915
916DL_EXPORT(void) initneo_cgi(void)
917{
918  PyObject *m, *d;
919  static void *NEO_PYTHON_API[P_NEO_CGI_POINTERS];
920  PyObject *c_api_object;
921
922  CGIObjectType.ob_type = &PyType_Type;
923
924
925
926  initneo_util();
927  _PyImport_FixupExtension("neo_util", "neo_util");
928
929  initneo_cs();
930  _PyImport_FixupExtension("neo_cs", "neo_cs");
931
932  m = Py_InitModule("neo_cgi", ModuleMethods);
933  p_cgiwrap_init (m);
934  d = PyModule_GetDict(m);
935  CGIFinishedException = PyErr_NewException("neo_cgi.CGIFinished", NULL, NULL);
936  PyDict_SetItemString(d, "CGIFinished", CGIFinishedException);
937
938  /* Initialize the C API Pointer array */
939  NEO_PYTHON_API[P_HDF_TO_OBJECT_NUM] = (void *)p_hdf_to_object;
940  NEO_PYTHON_API[P_OBJECT_TO_HDF_NUM] = (void *)p_object_to_hdf;
941  NEO_PYTHON_API[P_NEO_ERROR_NUM] = (void *)p_neo_error;
942
943  /* create a CObject containing the API pointer array's address */
944  c_api_object = PyCObject_FromVoidPtr((void *)NEO_PYTHON_API, NULL);
945  if (c_api_object != NULL) {
946    /* create a name for this object in the module's namespace */
947    PyDict_SetItemString(d, "_C_API", c_api_object);
948    Py_DECREF(c_api_object);
949    PyDict_SetItemString(d, "_C_API_NUM", PyInt_FromLong(P_NEO_CGI_POINTERS));
950  }
951}
952