Annotation of embedaddon/miniupnpc/miniupnpcmodule.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: miniupnpcmodule.c,v 1.21 2012/08/29 07:51:30 nanard Exp $*/
1.1       misho       2: /* Project : miniupnp
                      3:  * Author : Thomas BERNARD
                      4:  * website : http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho       5:  * copyright (c) 2007-2012 Thomas Bernard
1.1       misho       6:  * This software is subjet to the conditions detailed in the
                      7:  * provided LICENCE file. */
                      8: #include <Python.h>
                      9: #define STATICLIB
                     10: #include "structmember.h"
                     11: #include "miniupnpc.h"
                     12: #include "upnpcommands.h"
                     13: #include "upnperrors.h"
                     14: 
                     15: /* for compatibility with Python < 2.4 */
                     16: #ifndef Py_RETURN_NONE
                     17: #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
                     18: #endif
                     19: 
                     20: #ifndef Py_RETURN_TRUE
                     21: #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
                     22: #endif
                     23: 
                     24: #ifndef Py_RETURN_FALSE
                     25: #define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
                     26: #endif
                     27: 
1.1.1.2 ! misho      28: /* for compatibility with Python < 3.0 */
        !            29: #ifndef PyVarObject_HEAD_INIT
        !            30: #define PyVarObject_HEAD_INIT(type, size) \
        !            31:     PyObject_HEAD_INIT(type) size,
        !            32: #endif
        !            33: 
        !            34: #ifndef Py_TYPE
        !            35: #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
        !            36: #endif
        !            37: 
1.1       misho      38: typedef struct {
                     39:     PyObject_HEAD
                     40:     /* Type-specific fields go here. */
                     41:        struct UPNPDev * devlist;
                     42:        struct UPNPUrls urls;
                     43:        struct IGDdatas data;
                     44:        unsigned int discoverdelay;     /* value passed to upnpDiscover() */
                     45:        char lanaddr[40];       /* our ip address on the LAN */
                     46:        char * multicastif;
                     47:        char * minissdpdsocket;
                     48: } UPnPObject;
                     49: 
                     50: static PyMemberDef UPnP_members[] = {
                     51:        {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
                     52:         READONLY, "ip address on the LAN"
                     53:        },
                     54:        {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
                     55:         0/*READWRITE*/, "value in ms used to wait for SSDP responses"
                     56:        },
                     57:        /* T_STRING is allways readonly :( */
                     58:        {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
                     59:         0, "IP of the network interface to be used for multicast operations"
                     60:        },
                     61:        {"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif),
                     62:         0, "path of the MiniSSDPd unix socket"
                     63:        },
                     64:        {NULL}
                     65: };
                     66: 
                     67: static void
                     68: UPnPObject_dealloc(UPnPObject *self)
                     69: {
                     70:        freeUPNPDevlist(self->devlist);
                     71:        FreeUPNPUrls(&self->urls);
1.1.1.2 ! misho      72:        Py_TYPE(self)->tp_free((PyObject*)self);
1.1       misho      73: }
                     74: 
                     75: static PyObject *
                     76: UPnP_discover(UPnPObject *self)
                     77: {
                     78:        struct UPNPDev * dev;
                     79:        int i;
                     80:        PyObject *res = NULL;
                     81:        if(self->devlist)
                     82:        {
                     83:                freeUPNPDevlist(self->devlist);
                     84:                self->devlist = 0;
1.1.1.2 ! misho      85:        }
1.1       misho      86:        Py_BEGIN_ALLOW_THREADS
                     87:        self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
                     88:                                     0/* multicast if*/,
                     89:                                     0/*minissdpd socket*/,
                     90:                                                                 0/*sameport flag*/,
                     91:                                     0/*ip v6*/,
                     92:                                     0/*error */);
                     93:        Py_END_ALLOW_THREADS
                     94:        /* Py_RETURN_NONE ??? */
                     95:        for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
                     96:                i++;
                     97:        res = Py_BuildValue("i", i);
                     98:        return res;
                     99: }
                    100: 
                    101: static PyObject *
                    102: UPnP_selectigd(UPnPObject *self)
                    103: {
                    104:        int r;
                    105: Py_BEGIN_ALLOW_THREADS
                    106:        r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
                    107:                             self->lanaddr, sizeof(self->lanaddr));
                    108: Py_END_ALLOW_THREADS
                    109:        if(r)
                    110:        {
                    111:                return Py_BuildValue("s", self->urls.controlURL);
                    112:        }
                    113:        else
                    114:        {
                    115:                /* TODO: have our own exception type ! */
                    116:                PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
                    117:                return NULL;
                    118:        }
                    119: }
                    120: 
                    121: static PyObject *
                    122: UPnP_totalbytesent(UPnPObject *self)
                    123: {
                    124:        UNSIGNED_INTEGER i;
                    125: Py_BEGIN_ALLOW_THREADS
                    126:        i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
                    127:                                   self->data.CIF.servicetype);
                    128: Py_END_ALLOW_THREADS
                    129:        return Py_BuildValue("I", i);
                    130: }
                    131: 
                    132: static PyObject *
                    133: UPnP_totalbytereceived(UPnPObject *self)
                    134: {
                    135:        UNSIGNED_INTEGER i;
                    136: Py_BEGIN_ALLOW_THREADS
                    137:        i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
                    138:                                           self->data.CIF.servicetype);
                    139: Py_END_ALLOW_THREADS
                    140:        return Py_BuildValue("I", i);
                    141: }
                    142: 
                    143: static PyObject *
                    144: UPnP_totalpacketsent(UPnPObject *self)
                    145: {
                    146:        UNSIGNED_INTEGER i;
                    147: Py_BEGIN_ALLOW_THREADS
                    148:        i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
                    149:                                         self->data.CIF.servicetype);
                    150: Py_END_ALLOW_THREADS
                    151:        return Py_BuildValue("I", i);
                    152: }
                    153: 
                    154: static PyObject *
                    155: UPnP_totalpacketreceived(UPnPObject *self)
                    156: {
                    157:        UNSIGNED_INTEGER i;
                    158: Py_BEGIN_ALLOW_THREADS
                    159:        i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
                    160:                                          self->data.CIF.servicetype);
                    161: Py_END_ALLOW_THREADS
                    162:        return Py_BuildValue("I", i);
                    163: }
                    164: 
                    165: static PyObject *
                    166: UPnP_statusinfo(UPnPObject *self)
                    167: {
                    168:        char status[64];
                    169:        char lastconnerror[64];
                    170:        unsigned int uptime = 0;
                    171:        int r;
                    172:        status[0] = '\0';
                    173:        lastconnerror[0] = '\0';
                    174: Py_BEGIN_ALLOW_THREADS
                    175:        r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
                    176:                           status, &uptime, lastconnerror);
                    177: Py_END_ALLOW_THREADS
                    178:        if(r==UPNPCOMMAND_SUCCESS) {
                    179:                return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
                    180:        } else {
                    181:                /* TODO: have our own exception type ! */
                    182:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    183:                return NULL;
                    184:        }
                    185: }
                    186: 
                    187: static PyObject *
                    188: UPnP_connectiontype(UPnPObject *self)
                    189: {
                    190:        char connectionType[64];
                    191:        int r;
                    192:        connectionType[0] = '\0';
                    193: Py_BEGIN_ALLOW_THREADS
                    194:        r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
                    195:                                       self->data.first.servicetype,
                    196:                                       connectionType);
                    197: Py_END_ALLOW_THREADS
                    198:        if(r==UPNPCOMMAND_SUCCESS) {
                    199:                return Py_BuildValue("s", connectionType);
                    200:        } else {
                    201:                /* TODO: have our own exception type ! */
                    202:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    203:                return NULL;
                    204:        }
                    205: }
                    206: 
                    207: static PyObject *
                    208: UPnP_externalipaddress(UPnPObject *self)
                    209: {
                    210:        char externalIPAddress[40];
                    211:        int r;
                    212:        externalIPAddress[0] = '\0';
                    213: Py_BEGIN_ALLOW_THREADS
                    214:        r = UPNP_GetExternalIPAddress(self->urls.controlURL,
                    215:                                      self->data.first.servicetype,
                    216:                                      externalIPAddress);
                    217: Py_END_ALLOW_THREADS
                    218:        if(r==UPNPCOMMAND_SUCCESS) {
                    219:                return Py_BuildValue("s", externalIPAddress);
                    220:        } else {
                    221:                /* TODO: have our own exception type ! */
                    222:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    223:                return NULL;
                    224:        }
                    225: }
                    226: 
                    227: /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
1.1.1.2 ! misho     228:  *                remoteHost)
1.1       misho     229:  * protocol is 'UDP' or 'TCP' */
                    230: static PyObject *
                    231: UPnP_addportmapping(UPnPObject *self, PyObject *args)
                    232: {
                    233:        char extPort[6];
                    234:        unsigned short ePort;
                    235:        char inPort[6];
                    236:        unsigned short iPort;
                    237:        const char * proto;
                    238:        const char * host;
                    239:        const char * desc;
                    240:        const char * remoteHost;
                    241:        const char * leaseDuration = "0";
                    242:        int r;
                    243:        if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
                    244:                                             &host, &iPort, &desc, &remoteHost))
                    245:         return NULL;
                    246: Py_BEGIN_ALLOW_THREADS
                    247:        sprintf(extPort, "%hu", ePort);
                    248:        sprintf(inPort, "%hu", iPort);
                    249:        r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
                    250:                                extPort, inPort, host, desc, proto,
                    251:                                remoteHost, leaseDuration);
                    252: Py_END_ALLOW_THREADS
                    253:        if(r==UPNPCOMMAND_SUCCESS)
                    254:        {
                    255:                Py_RETURN_TRUE;
                    256:        }
                    257:        else
                    258:        {
                    259:                // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
                    260:                // upnperrors.c
                    261:                //Py_RETURN_FALSE;
                    262:                /* TODO: have our own exception type ! */
                    263:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    264:                return NULL;
                    265:        }
                    266: }
                    267: 
                    268: /* DeletePortMapping(extPort, proto, removeHost='')
                    269:  * proto = 'UDP', 'TCP' */
                    270: static PyObject *
                    271: UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
                    272: {
                    273:        char extPort[6];
                    274:        unsigned short ePort;
                    275:        const char * proto;
                    276:        const char * remoteHost = "";
                    277:        int r;
                    278:        if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
                    279:                return NULL;
                    280: Py_BEGIN_ALLOW_THREADS
                    281:        sprintf(extPort, "%hu", ePort);
                    282:        r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
                    283:                                   extPort, proto, remoteHost);
                    284: Py_END_ALLOW_THREADS
                    285:        if(r==UPNPCOMMAND_SUCCESS) {
                    286:                Py_RETURN_TRUE;
                    287:        } else {
                    288:                /* TODO: have our own exception type ! */
                    289:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    290:                return NULL;
                    291:        }
                    292: }
                    293: 
                    294: static PyObject *
                    295: UPnP_getportmappingnumberofentries(UPnPObject *self)
                    296: {
                    297:        unsigned int n = 0;
                    298:        int r;
                    299: Py_BEGIN_ALLOW_THREADS
                    300:        r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
                    301:                                           self->data.first.servicetype,
                    302:                                                                           &n);
                    303: Py_END_ALLOW_THREADS
                    304:        if(r==UPNPCOMMAND_SUCCESS) {
                    305:                return Py_BuildValue("I", n);
                    306:        } else {
                    307:                /* TODO: have our own exception type ! */
                    308:                PyErr_SetString(PyExc_Exception, strupnperror(r));
                    309:                return NULL;
                    310:        }
                    311: }
                    312: 
1.1.1.2 ! misho     313: /* GetSpecificPortMapping(ePort, proto)
1.1       misho     314:  * proto = 'UDP' or 'TCP' */
                    315: static PyObject *
                    316: UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
                    317: {
                    318:        char extPort[6];
                    319:        unsigned short ePort;
                    320:        const char * proto;
                    321:        char intClient[40];
                    322:        char intPort[6];
                    323:        unsigned short iPort;
                    324:        char desc[80];
                    325:        char enabled[4];
                    326:        char leaseDuration[16];
                    327:        if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto))
                    328:                return NULL;
                    329:        extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
                    330:        desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
                    331: Py_BEGIN_ALLOW_THREADS
                    332:        sprintf(extPort, "%hu", ePort);
                    333:        UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
                    334:                                         self->data.first.servicetype,
                    335:                                                                         extPort, proto,
                    336:                                                                         intClient, intPort,
                    337:                                         desc, enabled, leaseDuration);
                    338: Py_END_ALLOW_THREADS
                    339:        if(intClient[0])
                    340:        {
                    341:                iPort = (unsigned short)atoi(intPort);
                    342:                return Py_BuildValue("(s,H,s,O,i)",
                    343:                                     intClient, iPort, desc,
                    344:                                     PyBool_FromLong(atoi(enabled)),
                    345:                                     atoi(leaseDuration));
                    346:        }
                    347:        else
                    348:        {
                    349:                Py_RETURN_NONE;
                    350:        }
                    351: }
                    352: 
                    353: /* GetGenericPortMapping(index) */
                    354: static PyObject *
                    355: UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
                    356: {
                    357:        int i, r;
                    358:        char index[8];
                    359:        char intClient[40];
                    360:        char intPort[6];
                    361:        unsigned short iPort;
                    362:        char extPort[6];
                    363:        unsigned short ePort;
                    364:        char protocol[4];
                    365:        char desc[80];
                    366:        char enabled[6];
                    367:        char rHost[64];
                    368:        char duration[16];      /* lease duration */
                    369:        unsigned int dur;
                    370:        if(!PyArg_ParseTuple(args, "i", &i))
                    371:                return NULL;
                    372: Py_BEGIN_ALLOW_THREADS
                    373:        snprintf(index, sizeof(index), "%d", i);
                    374:        rHost[0] = '\0'; enabled[0] = '\0';
                    375:        duration[0] = '\0'; desc[0] = '\0';
                    376:        extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
                    377:        r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
                    378:                                            self->data.first.servicetype,
                    379:                                                                                index,
                    380:                                                                                extPort, intClient, intPort,
                    381:                                                                                protocol, desc, enabled, rHost,
                    382:                                                                                duration);
                    383: Py_END_ALLOW_THREADS
                    384:        if(r==UPNPCOMMAND_SUCCESS)
                    385:        {
                    386:                ePort = (unsigned short)atoi(extPort);
                    387:                iPort = (unsigned short)atoi(intPort);
                    388:                dur = (unsigned int)strtoul(duration, 0, 0);
                    389:                return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
                    390:                                     ePort, protocol, intClient, iPort,
                    391:                                     desc, enabled, rHost, dur);
                    392:        }
                    393:        else
                    394:        {
                    395:                Py_RETURN_NONE;
                    396:        }
                    397: }
                    398: 
                    399: /* miniupnpc.UPnP object Method Table */
                    400: static PyMethodDef UPnP_methods[] = {
                    401:     {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
                    402:      "discover UPnP IGD devices on the network"
                    403:     },
                    404:        {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
                    405:         "select a valid UPnP IGD among discovered devices"
                    406:        },
                    407:        {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
                    408:         "return the total number of bytes sent by UPnP IGD"
                    409:        },
                    410:        {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
                    411:         "return the total number of bytes received by UPnP IGD"
                    412:        },
                    413:        {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
                    414:         "return the total number of packets sent by UPnP IGD"
                    415:        },
                    416:        {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
                    417:         "return the total number of packets received by UPnP IGD"
                    418:        },
                    419:        {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
                    420:         "return status and uptime"
                    421:        },
                    422:        {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
                    423:         "return IGD WAN connection type"
                    424:        },
                    425:        {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
                    426:         "return external IP address"
                    427:        },
                    428:        {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
                    429:         "add a port mapping"
                    430:        },
                    431:        {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
                    432:         "delete a port mapping"
                    433:        },
                    434:        {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
                    435:         "-- non standard --"
                    436:        },
                    437:        {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
                    438:         "get details about a specific port mapping entry"
                    439:        },
                    440:        {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
                    441:         "get all details about the port mapping at index"
                    442:        },
                    443:     {NULL}  /* Sentinel */
                    444: };
                    445: 
                    446: static PyTypeObject UPnPType = {
1.1.1.2 ! misho     447:     PyVarObject_HEAD_INIT(NULL,
        !           448:     0)                         /*ob_size*/
1.1       misho     449:     "miniupnpc.UPnP",          /*tp_name*/
                    450:     sizeof(UPnPObject),        /*tp_basicsize*/
                    451:     0,                         /*tp_itemsize*/
                    452:     (destructor)UPnPObject_dealloc,/*tp_dealloc*/
                    453:     0,                         /*tp_print*/
                    454:     0,                         /*tp_getattr*/
                    455:     0,                         /*tp_setattr*/
                    456:     0,                         /*tp_compare*/
                    457:     0,                         /*tp_repr*/
                    458:     0,                         /*tp_as_number*/
                    459:     0,                         /*tp_as_sequence*/
                    460:     0,                         /*tp_as_mapping*/
                    461:     0,                         /*tp_hash */
                    462:     0,                         /*tp_call*/
                    463:     0,                         /*tp_str*/
                    464:     0,                         /*tp_getattro*/
                    465:     0,                         /*tp_setattro*/
                    466:     0,                         /*tp_as_buffer*/
                    467:     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
                    468:     "UPnP objects",            /* tp_doc */
                    469:     0,                            /* tp_traverse */
                    470:     0,                            /* tp_clear */
                    471:     0,                            /* tp_richcompare */
                    472:     0,                            /* tp_weaklistoffset */
                    473:     0,                            /* tp_iter */
                    474:     0,                            /* tp_iternext */
                    475:     UPnP_methods,              /* tp_methods */
                    476:     UPnP_members,              /* tp_members */
                    477:     0,                         /* tp_getset */
                    478:     0,                         /* tp_base */
                    479:     0,                         /* tp_dict */
                    480:     0,                         /* tp_descr_get */
                    481:     0,                         /* tp_descr_set */
                    482:     0,                         /* tp_dictoffset */
                    483:     0,/*(initproc)UPnP_init,*/      /* tp_init */
                    484:     0,                         /* tp_alloc */
1.1.1.2 ! misho     485: #ifndef _WIN32
1.1       misho     486:     PyType_GenericNew,/*UPnP_new,*/      /* tp_new */
                    487: #else
                    488:     0,
                    489: #endif
                    490: };
                    491: 
                    492: /* module methods */
                    493: static PyMethodDef miniupnpc_methods[] = {
                    494:     {NULL}  /* Sentinel */
                    495: };
                    496: 
1.1.1.2 ! misho     497: #if PY_MAJOR_VERSION >= 3
        !           498: static struct PyModuleDef moduledef = {
        !           499:     PyModuleDef_HEAD_INIT,
        !           500:     "miniupnpc",     /* m_name */
        !           501:     "miniupnpc module.",  /* m_doc */
        !           502:     -1,                  /* m_size */
        !           503:     miniupnpc_methods,    /* m_methods */
        !           504:     NULL,                /* m_reload */
        !           505:     NULL,                /* m_traverse */
        !           506:     NULL,                /* m_clear */
        !           507:     NULL,                /* m_free */
        !           508: };
        !           509: #endif
        !           510: 
1.1       misho     511: #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
                    512: #define PyMODINIT_FUNC void
                    513: #endif
1.1.1.2 ! misho     514: 
1.1       misho     515: PyMODINIT_FUNC
1.1.1.2 ! misho     516: #if PY_MAJOR_VERSION >= 3
        !           517: PyInit_miniupnpc(void)
        !           518: #else
        !           519: initminiupnpc(void)
        !           520: #endif
1.1       misho     521: {
                    522:     PyObject* m;
                    523: 
1.1.1.2 ! misho     524: #ifdef _WIN32
1.1       misho     525:     UPnPType.tp_new = PyType_GenericNew;
                    526: #endif
                    527:     if (PyType_Ready(&UPnPType) < 0)
                    528:         return;
                    529: 
1.1.1.2 ! misho     530: #if PY_MAJOR_VERSION >= 3
        !           531:     m = PyModule_Create(&moduledef);
        !           532: #else
1.1       misho     533:     m = Py_InitModule3("miniupnpc", miniupnpc_methods,
                    534:                        "miniupnpc module.");
1.1.1.2 ! misho     535: #endif
1.1       misho     536: 
                    537:     Py_INCREF(&UPnPType);
                    538:     PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
1.1.1.2 ! misho     539:     
        !           540: #if PY_MAJOR_VERSION >= 3
        !           541:     return m;
        !           542: #endif
1.1       misho     543: }
                    544: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>