/* teamtrack-module.cpp -- Python extension interfacing to TeamTrack Gareth Rees, Ravenbrook Limited, 2000-08-02 $Id: //info.ravenbrook.com/project/p4dti/version/0.2/code/python-teamtrack-interface/teamtrack-module.cpp#1 $ */ #include "teamtrack-module.h" #include "teamtrack-server.h" #include "TSServer.h" /* Objects representing Python exceptions. They are assigned in initteamtrack(). */ /* teamtrack_error represents errors that represents errors generated by this interface module. In Python it's called teamtrack.error. */ PyObject *teamtrack_error; /* teamtrack_tsapi_error represents errors generated by the TeamShare API. In Python it's called teamtrack.tsapi_error. */ static PyObject *teamtrack_tsapi_error; /* teamtrack_set_error(server) sets the current Python error to the most recent TeamTrack error for the given TeamShare server. */ void teamtrack_set_error(TSServer *server) { char *error_name; switch(TSGetLastError()) { case TS_ERROR: error_name = "ERROR"; break; case TS_INVALID_DATA_TYPE: error_name = "INVALID_DATA_TYPE"; break; case TS_NO_PERMISSION: error_name = "NO_PERMISSION"; break; case TS_NO_SUCH_FIELD: error_name = "NO_SUCH_FIELD"; break; case TS_MEMORY_ERROR: error_name = "MEMORY_ERROR"; break; case TS_SOCKET_READ_ERROR: error_name = "SOCKET_READ_ERROR"; break; case TS_SOCKET_WRITE_ERROR: error_name = "SOCKET_WRITE_ERROR"; break; case TS_SOCKET_CONNECT_FAILED: error_name = "SOCKET_CONNECT_FAILED"; break; case TS_SOCKET_CREATE_FAILED: error_name = "SOCKET_CREATE_FAILED"; break; case TS_INVALID_DATATYPE: error_name = "INVALID_DATATYPE"; break; case TS_INVALID_USER: error_name = "INVALID_USER"; break; case TS_NO_RESULTS: error_name = "NO_RESULTS"; break; case TS_SERVER_ERROR: error_name = "SERVER_ERROR"; break; case TS_INVALID_VERSION: error_name = "INVALID_VERSION"; break; default: error_name = "(unknown)"; break; } PyObject *separator = PyString_FromString(": "); const char *ts_message = server->GetLastErrorMessage(); PyObject *error_message; if (ts_message) { error_message = PyString_FromString(ts_message); } else { error_message = PyString_FromString("(no message from the TeamShare API)"); } PyObject *message = PyString_FromString(error_name); PyString_ConcatAndDel(&message, separator); PyString_ConcatAndDel(&message, error_message); PyErr_SetObject(teamtrack_tsapi_error, message); Py_XDECREF(message); /* Owned by Python's exception handler. */ } /* teamtrack.connect(user,password,hostname) connects to a TeamShare server on hostname with the given user and password and returns an object representing that server. */ static PyObject * teamtrack_connect(PyObject *self, PyObject *args) { char *user; char *password; char *hostname; if (!PyArg_ParseTuple(args, "sss", &user, &password, &hostname)) return 0; TSServer *s = new TSServer; if (!s) return 0; if (s->Connect(user, password, hostname) != TS_OK) { teamtrack_set_error(s); delete s; return 0; } return teamtrack_server_new(s, 1); } static PyMethodDef teamtrack_methods[] = { { "connect", teamtrack_connect, METH_VARARGS }, { NULL, NULL } /* End of methods. */ }; typedef struct { char *name; int id; } string_to_int_map; /* teamtrack_make_map(c_map, size, name, dict) turns the C map c_map (with size items) into a Python map, and installs it with the given name in the given dictionary. */ void teamtrack_make_map(string_to_int_map c_map[], size_t size, char *name, PyObject *dict) { PyObject *py_map = PyDict_New(); PyDict_SetItemString(dict, name, py_map); for (int i = 0; i < size; ++i) { PyObject *id = PyInt_FromLong((long)c_map[i].id); PyDict_SetItemString(py_map, c_map[i].name, id); Py_XDECREF(id); /* Owned by py_map. */ } Py_XDECREF(py_map); /* Owned by dict. */ } /* teamtrack_table[] is used to initialize the teamtrack.table dictionary that maps table name to table id. The table identifiers appear in TSDef.h. */ string_to_int_map teamtrack_table[] = { { "CASES", TS_TBLID_CASES }, { "CHANGES", TS_TBLID_CHANGES }, { "FIELDS", TS_TBLID_FIELDS }, { "GROUPS", TS_TBLID_GROUPS }, { "LICENSES", TS_TBLID_LICENSES }, { "MEMBERS", TS_TBLID_MEMBERS }, { "PRIVILEGES", TS_TBLID_PRIVILEGES }, { "PROJECTS", TS_TBLID_PROJECTS }, { "PROJECTSELECTIONS", TS_TBLID_PROJECTSELECTIONS }, { "PROPERTIES", TS_TBLID_PROPERTIES }, { "REPORTS", TS_TBLID_REPORTS }, { "SELECTIONS", TS_TBLID_SELECTIONS }, { "STATES", TS_TBLID_STATES }, { "TRANSISSUETYPES", TS_TBLID_TRANSISSUETYPES }, { "SYSTEMINFO", TS_TBLID_SYSTEMINFO }, { "TRANSITIONS", TS_TBLID_TRANSITIONS }, { "USERS", TS_TBLID_USERS }, { "TABLES", TS_TBLID_TABLES }, { "ATTACHMENTS", TS_TBLID_ATTACHMENTS }, { "FOLDERS", TS_TBLID_FOLDERS }, { "FOLDERITEMS", TS_TBLID_FOLDERITEMS }, { "FOLDERCOLUMNS", TS_TBLID_FOLDERCOLUMNS }, { "VCACTIONS", TS_TBLID_VCACTIONS }, { "PROJECTTRANSITIONS", TS_TBLID_PROJECTTRANSITIONS }, { "NOTIFICATIONS", TS_TBLID_NOTIFICATIONS }, { "NOTIFICATIONRULES", TS_TBLID_NOTIFICATIONRULES }, { "NOTIFICATIONCONDITIONS", TS_TBLID_NOTIFICATIONCONDITIONS }, { "NOTIFICATIONEVENTS", TS_TBLID_NOTIFICATIONEVENTS }, { "NOTIFICATIONFIELDS", TS_TBLID_NOTIFICATIONFIELDS }, { "NOTIFICATIONMESSAGES", TS_TBLID_NOTIFICATIONMESSAGES }, { "NOTIFICATIONPERMISSIONS", TS_TBLID_NOTIFICATIONPERMISSIONS }, { "NOTIFICATIONSUBSCRIPTIONS", TS_TBLID_NOTIFICATIONSUBSCRIPTIONS }, { "MACROS", TS_TBLID_MACROS }, { "WORKFLOWS", TS_TBLID_WORKFLOWS }, { "FIELDORDERINGS", TS_TBLID_FIELDORDERINGS }, { "INCIDENTS", TS_TBLID_INCIDENTS }, { "COMPANIES", TS_TBLID_COMPANIES }, { "CONTACTS", TS_TBLID_CONTACTS }, { "MERCHANDISE", TS_TBLID_MERCHANDISE }, { "SERVICEAGREEMENTS", TS_TBLID_SERVICEAGREEMENTS }, { "PROBLEMS", TS_TBLID_PROBLEMS }, { "RESOLUTIONS", TS_TBLID_RESOLUTIONS }, { "PRODUCTS", TS_TBLID_PRODUCTS }, { "KEYWORDS", TS_TBLID_KEYWORDS }, { "PRODUCTUSAGES", TS_TBLID_PRODUCTUSAGES }, { "KEYWORDUSAGES", TS_TBLID_KEYWORDUSAGES }, { "TRANSTRIGGERS", TS_TBLID_TRANSTRIGGERS }, { "TRANSTRIGGERSTATES", TS_TBLID_TRANSTRIGGERSTATES }, { "TRANSTRIGGERTRANSITIONS", TS_TBLID_TRANSTRIGGERTRANSITIONS }, }; /* teamtrack_field_type[] is used to initialize the teamtrack.field_type dictionary that maps field type name to field type id. The field type identifiers appear in TSDef.h. */ string_to_int_map teamtrack_field_type[] = { { "NUMERIC", TS_FLDTYPE_NUMERIC }, { "TEXT", TS_FLDTYPE_TEXT }, { "MEMO", TS_FLDTYPE_MEMO }, { "DATETIME", TS_FLDTYPE_DATETIME }, { "SELECTION", TS_FLDTYPE_SELECTION }, { "BINARY", TS_FLDTYPE_BINARY }, { "STATE", TS_FLDTYPE_STATE }, { "USER", TS_FLDTYPE_USER }, { "PROJECT", TS_FLDTYPE_PROJECT }, { "SUMMATION", TS_FLDTYPE_SUMMATION }, { "MULTIPLE_SELECTION", TS_FLDTYPE_MULTIPLE_SELECTION }, { "CONTACT", TS_FLDTYPE_CONTACT }, { "COMPANY", TS_FLDTYPE_COMPANY }, { "INCIDENT", TS_FLDTYPE_INCIDENT }, { "PRODUCT", TS_FLDTYPE_PRODUCT }, { "SERVICEAGREEMENT", TS_FLDTYPE_SERVICEAGREEMENT }, { "FOLDER", TS_FLDTYPE_FOLDER }, { "KEYWORDLIST", TS_FLDTYPE_KEYWORDLIST }, { "PRODUCTLIST", TS_FLDTYPE_PRODUCTLIST }, { "PROBLEM", TS_FLDTYPE_PROBLEM }, { "RESOLUTION", TS_FLDTYPE_RESOLUTION }, { "MERCHANDISE", TS_FLDTYPE_MERCHANDISE }, }; extern "C" void TEAMTRACK_EXPORTED initteamtrack() { /* Create the "teamtrack" module. */ PyObject *m = Py_InitModule("teamtrack", teamtrack_methods); PyObject *d = PyModule_GetDict(m); /* Create an object to represent errors in the Python interface to TeamTrack (a string with the value "TeamTrack interface error") and give it the Python name "teamtrack.error". */ teamtrack_error = PyString_FromString("TeamTrack interface error"); PyDict_SetItemString(d, "error", teamtrack_error); /* Don't decref teamtrack_error since we continue to own it through a global variable. */ /* Create an object to represent TeamTrack errors (a string with the value "TeamTrack error") and give it the Python name "teamtrack.error". */ teamtrack_tsapi_error = PyString_FromString("TeamShare API error"); PyDict_SetItemString(d, "tsapi_error", teamtrack_tsapi_error); /* Don't decref teamtrack_tsapi_error since we continue to own it through a global variable. */ /* Make teamtrack.tables (a mapping from table name to table id). */ teamtrack_make_map(teamtrack_table, sizeof(teamtrack_table) / sizeof(teamtrack_table[0]), "table", d); /* Make teamtrack.tables (a mapping from table name to table id). */ teamtrack_make_map(teamtrack_field_type, sizeof(teamtrack_field_type) / sizeof(teamtrack_field_type[0]), "field_type", d); /* Check for errors that occurred during module initialization. */ if (PyErr_Occurred()) { Py_FatalError("Can't initialise teamtrack module."); } #if defined(WIN32) if (TSInitializeWinsock() != TS_OK) { Py_FatalError("Can't initialise Winsock."); } #endif /* defined(WIN32) */ }