/* teamtrack-module.cpp -- Python extension interfacing to TeamTrack Gareth Rees, Ravenbrook Limited, 2000-08-02 $Id: //info.ravenbrook.com/project/p4dti/branch/2000-11-29/bugzilla-resolution/code/python-teamtrack-interface/teamtrack-module.cpp#1 $ See "Python interface to TeamTrack: design" for the design. */ /* Copyright 2000 Ravenbrook Limited. This document is provided "as is", without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this document. You may make and distribute copies and derivative works of this document provided that (1) you do not charge a fee for this document or for its distribution, and (2) you retain as they appear all copyright and licence notices and document history entries, and (3) you append descriptions of your modifications to the document history. */ #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 != NULL) { 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 NULL; } TSServer *s = new TSServer; if (s == NULL) { return NULL; } if (s->Connect(user, password, hostname) != TS_OK) { teamtrack_set_error(s); delete s; return NULL; } 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) */ }